Compare commits
89
Commits
+1
-1
@@ -1,4 +1,4 @@
|
||||
/hscript.swf
|
||||
/release.zip
|
||||
|
||||
dump/*
|
||||
tests/bin/*
|
||||
@@ -1,16 +1,29 @@
|
||||
hscript-improved
|
||||
=======
|
||||
|
||||
- [Features](docs/FEATURES.md)
|
||||
|
||||
How to install
|
||||
```
|
||||
haxelib git hscript-improved https://github.com/FNF-CNE-Devs/hscript-improved.git
|
||||
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git
|
||||
```
|
||||
|
||||
To enable custom classes support you have to do this in project.xml
|
||||
|
||||
```xml
|
||||
<define name="CUSTOM_CLASSES" />
|
||||
```
|
||||
Warning: custom classes are sometimes broken, would like help to fix them. You can only override functions from the current class, not from the extended part, like you cant override update in FlxText because FlxText doesnt have a update function overriden
|
||||
|
||||
or set this in build.hxml
|
||||
|
||||
```hxml
|
||||
-D CUSTOM_CLASSES
|
||||
```
|
||||
|
||||
Current Custom Class Limitations :
|
||||
|
||||
- For now, you can only override functions from the current class, not from the extended part, like you cant override update in FlxText because FlxText doesnt have a update function overriden.
|
||||
- You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
|
||||
|
||||
-----------
|
||||
|
||||
|
||||
@@ -26,13 +26,8 @@ class TestHScript extends TestCase {
|
||||
assertScript("0",0);
|
||||
assertScript("0xFF", 255);
|
||||
#if !(php || python)
|
||||
#if haxe3
|
||||
assertScript("0xBFFFFFFF", 0xBFFFFFFF);
|
||||
assertScript("0x7FFFFFFF", 0x7FFFFFFF);
|
||||
#elseif !neko
|
||||
assertScript("n(0xBFFFFFFF)", 0xBFFFFFFF, { n : haxe.Int32.toNativeInt });
|
||||
assertScript("n(0x7FFFFFFF)", 0x7FFFFFFF, { n : haxe.Int32.toNativeInt } );
|
||||
#end
|
||||
#end
|
||||
assertScript("-123",-123);
|
||||
assertScript("- 123",-123);
|
||||
@@ -81,11 +76,7 @@ class TestHScript extends TestCase {
|
||||
assertScript("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10);
|
||||
assertScript("var a = false; do { a = true; } while (!a); a;",true);
|
||||
assertScript("var t = 0; for( x in 1...10 ) t += x; t", 45);
|
||||
#if haxe3
|
||||
assertScript("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45);
|
||||
#else
|
||||
assertScript("var t = 0; for( x in new IntIter(1,10) ) t +=x; t", 45);
|
||||
#end
|
||||
assertScript("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",790);
|
||||
assertScript("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",56);
|
||||
assertScript("var i=2; if( true ) --i; i",1);
|
||||
|
||||
@@ -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
-2
@@ -1,4 +1,3 @@
|
||||
--macro keep('IntIterator')
|
||||
--macro hscript.macros.UsingHandler.init()
|
||||
--macro hscript.macros.AbstractHandler.init()
|
||||
--macro hscript.macros.ClassExtendMacro.init()
|
||||
--define HSCRIPT_NEW
|
||||
|
||||
+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",
|
||||
|
||||
+7
-7
@@ -153,11 +153,11 @@ class Async {
|
||||
}
|
||||
|
||||
inline function fun(arg:String, e, ?name) {
|
||||
return mk(EFunction([{ name : arg, t : null }], e, name), e);
|
||||
return mk(EFunction([{ name : arg, t : null, opt: false, value: null }], e, name), e);
|
||||
}
|
||||
|
||||
inline function funs(arg:Array<String>, e, ?name) {
|
||||
return mk(EFunction([for( a in arg ) { name : a, t : null }], e, name), e);
|
||||
return mk(EFunction([for( a in arg ) { name : a, t : null, opt: false, value: null }], e, name), e);
|
||||
}
|
||||
|
||||
inline function block(arr:Array<Expr>, e) {
|
||||
@@ -260,7 +260,7 @@ class Async {
|
||||
defineVar(name, Defined);
|
||||
for( a in args )
|
||||
defineVar(a.name, Defined);
|
||||
args.unshift( { name : "_onEnd", t : null } );
|
||||
args.unshift( { name : "_onEnd", t : null, opt: false, value: null } );
|
||||
var frest = ident("_onEnd",e);
|
||||
var oldFun = currentFun;
|
||||
currentFun = name;
|
||||
@@ -417,10 +417,10 @@ class Async {
|
||||
if( currentLoop == null ) throw "Continue outside loop";
|
||||
return block([retNull(currentLoop, e), mk(EReturn(),e)], e);
|
||||
case ESwitch(v, cases, def):
|
||||
var cases = [for( c in cases ) { values : c.values, expr : toCps(c.expr, rest, exit) } ];
|
||||
return toCps(v, mk(EFunction([ { name : "_c", t : null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
||||
var cases:Array<SwitchCase> = [for( c in cases ) { values : c.values, expr : toCps(c.expr, rest, exit) } ];
|
||||
return toCps(v, mk(EFunction([ { name : "_c", t : null, opt: false, value: null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
||||
case EThrow(v):
|
||||
return toCps(v, mk(EFunction([ { name : "_v", t : null } ], mk(EThrow(v),v)), v), exit);
|
||||
return toCps(v, mk(EFunction([ { name : "_v", t : null, opt: false, value: null } ], mk(EThrow(v),v)), v), exit);
|
||||
case EMeta(name,_,e) if( name.charCodeAt(0) == ":".code ): // ignore custom ":" metadata
|
||||
return toCps(e, rest, exit);
|
||||
//case EDoWhile(_), ETry(_), ECall(_):
|
||||
@@ -436,7 +436,7 @@ class AsyncInterp extends Interp {
|
||||
|
||||
public function setContext( api : Dynamic ) {
|
||||
|
||||
var funs = new Array();
|
||||
var funs = [];
|
||||
for( v in variables.keys() )
|
||||
if( Reflect.isFunction(variables.get(v)) )
|
||||
funs.push({ v : v, obj : null });
|
||||
|
||||
+18
-26
@@ -27,7 +27,7 @@ class Bytes {
|
||||
var bin : haxe.io.Bytes;
|
||||
var bout : haxe.io.BytesBuffer;
|
||||
var pin : Int;
|
||||
var hstrings : #if haxe3 Map<String,Int> #else Hash<Int> #end;
|
||||
var hstrings : Map<String,Int>;
|
||||
var strings : Array<String>;
|
||||
var nstrings : Int;
|
||||
|
||||
@@ -35,7 +35,7 @@ class Bytes {
|
||||
this.bin = bin;
|
||||
pin = 0;
|
||||
bout = new haxe.io.BytesBuffer();
|
||||
hstrings = #if haxe3 new Map() #else new Hash() #end;
|
||||
hstrings = new Map();
|
||||
strings = [null];
|
||||
nstrings = 1;
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class Bytes {
|
||||
var vid = hstrings.get(v);
|
||||
if( vid == null ) {
|
||||
if( nstrings == 256 ) {
|
||||
hstrings = #if haxe3 new Map() #else new Hash() #end;
|
||||
hstrings = new Map();
|
||||
nstrings = 1;
|
||||
}
|
||||
hstrings.set(v,nstrings);
|
||||
@@ -85,15 +85,6 @@ class Bytes {
|
||||
bout.addByte(1);
|
||||
doEncodeInt(v);
|
||||
}
|
||||
#if !haxe3
|
||||
case CInt32(v):
|
||||
bout.addByte(4);
|
||||
var mid = haxe.Int32.toInt(haxe.Int32.and(v,haxe.Int32.ofInt(0xFFFFFF)));
|
||||
bout.addByte(mid & 0xFF);
|
||||
bout.addByte((mid >> 8) & 0xFF);
|
||||
bout.addByte(mid >> 16);
|
||||
bout.addByte(haxe.Int32.toInt(haxe.Int32.ushr(v, 24)));
|
||||
#end
|
||||
case CFloat(f):
|
||||
bout.addByte(2);
|
||||
doEncodeString(Std.string(f));
|
||||
@@ -120,13 +111,6 @@ class Bytes {
|
||||
CFloat( Std.parseFloat(doDecodeString()) );
|
||||
case 3:
|
||||
CString( doDecodeString() );
|
||||
#if !haxe3
|
||||
case 4:
|
||||
var i = bin.get(pin) | (bin.get(pin+1) << 8) | (bin.get(pin+2) << 16);
|
||||
var j = bin.get(pin+3);
|
||||
pin += 4;
|
||||
CInt32(haxe.Int32.or(haxe.Int32.ofInt(i), haxe.Int32.shl(haxe.Int32.ofInt(j), 24)));
|
||||
#end
|
||||
default:
|
||||
throw "Invalid code "+bin.get(pin-1);
|
||||
}
|
||||
@@ -140,10 +124,18 @@ class Bytes {
|
||||
#end
|
||||
bout.addByte(Type.enumIndex(e));
|
||||
switch( e ) {
|
||||
case EPackage(n):
|
||||
// TODO
|
||||
case EImport(c):
|
||||
// TODO
|
||||
case EClass(_, _, _, _):
|
||||
// TODO
|
||||
case EEnum(en):
|
||||
// TODO
|
||||
case ECast(e, _):
|
||||
// TODO
|
||||
case ERegex(e, f):
|
||||
// TODO
|
||||
case EConst(c):
|
||||
doEncodeConst(c);
|
||||
case EIdent(v):
|
||||
@@ -278,7 +270,7 @@ class Bytes {
|
||||
case 3:
|
||||
EParent(doDecode());
|
||||
case 4:
|
||||
var a = new Array();
|
||||
var a = [];
|
||||
for( i in 0...bin.get(pin++) )
|
||||
a.push(doDecode());
|
||||
EBlock(a);
|
||||
@@ -295,7 +287,7 @@ class Bytes {
|
||||
EUnop(op,prefix,doDecode());
|
||||
case 8:
|
||||
var e = doDecode();
|
||||
var params = new Array();
|
||||
var params = [];
|
||||
for( i in 0...bin.get(pin++) )
|
||||
params.push(doDecode());
|
||||
ECall(e,params);
|
||||
@@ -317,7 +309,7 @@ class Bytes {
|
||||
case 14:
|
||||
var params = new Array<Argument>();
|
||||
for( i in 0...bin.get(pin++) )
|
||||
params.push({ name : doDecodeString() });
|
||||
params.push({ name : doDecodeString(), opt: false, value: null, t: null });
|
||||
var e = doDecode();
|
||||
var name = doDecodeString();
|
||||
EFunction(params,e,(name == "") ? null: name);
|
||||
@@ -327,13 +319,13 @@ class Bytes {
|
||||
var e = doDecode();
|
||||
EArray(e,doDecode());
|
||||
case 17:
|
||||
var el = new Array();
|
||||
var el = [];
|
||||
for( i in 0...bin.get(pin++) )
|
||||
el.push(doDecode());
|
||||
EArrayDecl(el);
|
||||
case 18:
|
||||
var cl = doDecodeString();
|
||||
var el = new Array();
|
||||
var el = [];
|
||||
for( i in 0...bin.get(pin++) )
|
||||
el.push(doDecode());
|
||||
ENew(cl,el);
|
||||
@@ -344,7 +336,7 @@ class Bytes {
|
||||
var v = doDecodeString();
|
||||
ETry(e,v,null,doDecode());
|
||||
case 21:
|
||||
var fl = new Array();
|
||||
var fl:Array<ObjectField> = [];
|
||||
for( i in 0...bin.get(pin++) ) {
|
||||
var name = doDecodeString();
|
||||
var e = doDecode();
|
||||
@@ -358,7 +350,7 @@ class Bytes {
|
||||
ETernary(cond, e1, e2);
|
||||
case 23:
|
||||
var e = doDecode();
|
||||
var cases = [];
|
||||
var cases:Array<SwitchCase> = [];
|
||||
while( true ) {
|
||||
var v = doDecode();
|
||||
if( v == null ) break;
|
||||
|
||||
@@ -422,6 +422,9 @@ class Checker {
|
||||
return makeType(t,e);
|
||||
case CTOpt(t):
|
||||
return makeType(t,e);
|
||||
case CTExpr(_):
|
||||
error("Unsupported expr type parameter", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,355 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.utils.UnsafeReflect;
|
||||
import haxe.Constraints.Function;
|
||||
|
||||
using Lambda;
|
||||
|
||||
/**
|
||||
* The Custom Class core.
|
||||
*
|
||||
* Provides handlers for custom classes.
|
||||
*
|
||||
* @author Jamextreme140
|
||||
*/
|
||||
@:access(hscript.CustomClassHandler)
|
||||
@:access(hscript.Property)
|
||||
class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
public var className(get, never):String;
|
||||
|
||||
private function get_className():String
|
||||
return __class.name;
|
||||
|
||||
public var __interp:Interp;
|
||||
public var __real_fields:Array<String> = []; // UNUSED
|
||||
public var __class__fields:Array<String> = []; // Declared fields
|
||||
|
||||
public var __allowSetGet:Bool = true;
|
||||
|
||||
var __class:CustomClassHandler;
|
||||
var __superClass:IHScriptCustomClassBehaviour;
|
||||
var __upperClass:IHScriptCustomClassBehaviour;
|
||||
var __constructor:Function;
|
||||
|
||||
var __overrideFields:Array<String> = [];
|
||||
var __cachedFieldSet:Map<String, Dynamic> = null;
|
||||
var initializing:Bool = false;
|
||||
|
||||
public function new(__class:CustomClassHandler, ?args:Array<Dynamic>, ?cachedFieldSet:Map<String, Dynamic>) {
|
||||
this.__class = __class;
|
||||
|
||||
__interp = new Interp();
|
||||
__interp.errorHandler = __class.__interp.errorHandler;
|
||||
__interp.importFailedCallback = __class.__interp.importFailedCallback;
|
||||
|
||||
// __interp.variables = __class.staticInterp.variables;
|
||||
@:privateAccess __interp.usingHandler.usingEntries = __class.ogInterp.usingHandler.usingEntries;
|
||||
__interp.publicVariables = __class.ogInterp.publicVariables;
|
||||
__interp.staticVariables = __class.ogInterp.staticVariables;
|
||||
__interp.customClasses = __class.ogInterp.customClasses;
|
||||
|
||||
for(f => v in __class.__interp.variables) {
|
||||
if(f == 'new') continue;
|
||||
if (!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
}
|
||||
|
||||
for (f in __class.fields) {
|
||||
switch (Tools.expr(f)) {
|
||||
case EVar(n): __class__fields.push(n);
|
||||
case EFunction(_, _, n, _, _, _, isOverride):
|
||||
if(isOverride) __overrideFields.push(n);
|
||||
__class__fields.push(n);
|
||||
default: continue;
|
||||
}
|
||||
@:privateAccess __interp.exprReturn(f);
|
||||
}
|
||||
|
||||
__interp.scriptObject = this;
|
||||
|
||||
initializing = true;
|
||||
|
||||
if(cachedFieldSet != null)
|
||||
for(f => v in cachedFieldSet)
|
||||
this.hset(f, v);
|
||||
|
||||
if (hasField('new')) {
|
||||
buildConstructor();
|
||||
call('new', args);
|
||||
|
||||
if(__cachedFieldSet != null) {
|
||||
__cachedFieldSet.clear();
|
||||
__cachedFieldSet = null;
|
||||
}
|
||||
|
||||
if (this.__superClass == null && __class.extend != null)
|
||||
__interp.error(ECustom("super() not called"));
|
||||
} else if (__class.extend != null) {
|
||||
buildSuperClass(args);
|
||||
}
|
||||
|
||||
initializing = false;
|
||||
}
|
||||
|
||||
function cacheFieldSet(name:String, val:Dynamic) {
|
||||
if(!initializing) return;
|
||||
if(__cachedFieldSet == null) __cachedFieldSet = [];
|
||||
__cachedFieldSet.set(name, val);
|
||||
}
|
||||
|
||||
function buildConstructor() {
|
||||
__constructor = Reflect.makeVarArgs(buildSuperClass);
|
||||
}
|
||||
|
||||
function buildSuperClass(?args:Array<Dynamic>) {
|
||||
if (args == null)
|
||||
args = [];
|
||||
|
||||
if (__class.cl == null) {
|
||||
__interp.error(ECustom('Current class does not have a super'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (__class.cl is CustomClassHandler) {
|
||||
var customClass = new CustomClass(__class.cl, args, __cachedFieldSet);
|
||||
if(__overrideFields.length > 0) {
|
||||
for (field in __overrideFields) {
|
||||
var func = __interp.variables.get(field);
|
||||
customClass.overrideField(field, func);
|
||||
}
|
||||
}
|
||||
customClass.__upperClass = this;
|
||||
__superClass = customClass;
|
||||
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(getSuperFields());
|
||||
} else {
|
||||
if(__cachedFieldSet != null)
|
||||
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
|
||||
|
||||
__superClass = Type.createInstance(__class.cl, args);
|
||||
var disallowCopy:Array<String> = {
|
||||
var fieldMap:Map<String, String> = []; // Prevent duplicate values
|
||||
for(f in Reflect.fields(__superClass).concat(Type.getInstanceFields(Type.getClass(__superClass))))
|
||||
fieldMap.set(f, f);
|
||||
|
||||
fieldMap.array();
|
||||
}
|
||||
this.__real_fields = disallowCopy;
|
||||
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(disallowCopy);
|
||||
__superClass.__real_fields = this.__real_fields;
|
||||
__superClass.__class__fields = this.__class__fields;
|
||||
__superClass.__interp = this.__interp;
|
||||
}
|
||||
}
|
||||
|
||||
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
|
||||
var superFnName:Null<String> = toSuper ? '_HX_SUPER__$name' : null;
|
||||
var fn:Dynamic = {
|
||||
if(toSuper && __interp.variables.exists(superFnName)) {
|
||||
__interp.variables.get(superFnName);
|
||||
}
|
||||
else
|
||||
__interp.variables.get(name);
|
||||
};
|
||||
|
||||
if (fn != null && Reflect.isFunction(fn))
|
||||
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
|
||||
else
|
||||
__interp.error(ECustom('$name doesn\'t exists or is not a function'));
|
||||
return null;
|
||||
}
|
||||
|
||||
function hasField(name:String) {
|
||||
return __class__fields.contains(name);
|
||||
}
|
||||
|
||||
function hasStaticField(name:String):Bool {
|
||||
return __class.hasField(name);
|
||||
}
|
||||
|
||||
function getField(name:String, allowProperty:Bool = true):Dynamic {
|
||||
var f = __interp.variables.get(name);
|
||||
if (f != null && allowProperty && f is Property) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callGetter(name);
|
||||
prop.__allowSetGet = null;
|
||||
return r;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
function setField(name:String, val:Dynamic):Dynamic {
|
||||
var f = getField(name, false);
|
||||
if (f != null && f is Property) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callSetter(name, val);
|
||||
prop.__allowSetGet = null;
|
||||
return r;
|
||||
}
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides (replaces) the declared function.
|
||||
* @param name
|
||||
* @param func
|
||||
*/
|
||||
function overrideField(name:String, func:Function) {
|
||||
var f = getField(name, false);
|
||||
if(f != null && Reflect.isFunction(f)) {
|
||||
__interp.variables.set(name, func);
|
||||
__interp.variables.set('_HX_SUPER__$name', f);
|
||||
}
|
||||
else if(__superClass != null && __superClass is CustomClass) {
|
||||
cast(__superClass, CustomClass).overrideField(name, func);
|
||||
}
|
||||
}
|
||||
|
||||
function superHasField(name:String) {
|
||||
if (__superClass == null)
|
||||
return false;
|
||||
|
||||
var realFieldExists = __superClass.__real_fields != null && __superClass.__real_fields.contains(name);
|
||||
var classFieldExists = __superClass.__class__fields != null && __superClass.__class__fields.contains(name);
|
||||
|
||||
if(!realFieldExists && !classFieldExists && __superClass is CustomClass)
|
||||
return cast(__superClass, CustomClass).superHasField(name);
|
||||
|
||||
return realFieldExists || classFieldExists;
|
||||
}
|
||||
|
||||
function getSuperFields():Array<String> {
|
||||
if(__superClass == null) return [];
|
||||
|
||||
var classFields:Map<String, String> = []; // Prevents duplicated values
|
||||
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
|
||||
|
||||
while (cls != null) {
|
||||
for(fieldSet in [cls.__class__fields, cls.__real_fields])
|
||||
for(f in fieldSet)
|
||||
classFields.set(f, f);
|
||||
var next:IHScriptCustomClassBehaviour = null;
|
||||
if(cls is CustomClass)
|
||||
next = cast(cls, CustomClass).__superClass;
|
||||
if (next == null)
|
||||
break;
|
||||
cls = next;
|
||||
}
|
||||
|
||||
return [for(f in classFields) f];
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
switch (name) {
|
||||
case 'superClass': return __superClass;
|
||||
case 'superConstructor': return __constructor;
|
||||
default:
|
||||
if (hasField(name))
|
||||
return getField(name);
|
||||
|
||||
if (hasStaticField(name)) {
|
||||
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (__superClass != null) {
|
||||
if (superHasField(name)) {
|
||||
__superClass.__allowSetGet = this.__allowSetGet;
|
||||
return __superClass.hget(name);
|
||||
}
|
||||
}
|
||||
|
||||
throw "field '"
|
||||
+ name
|
||||
+ "' does not exist in custom class '"
|
||||
+ this.className
|
||||
+ "'"
|
||||
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if (hasField(name))
|
||||
return setField(name, val);
|
||||
|
||||
if (hasStaticField(name)) {
|
||||
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (__superClass != null) {
|
||||
if (superHasField(name)) {
|
||||
__superClass.__allowSetGet = this.__allowSetGet;
|
||||
return __superClass.hset(name, val);
|
||||
}
|
||||
}
|
||||
else if(__class.extend != null && initializing) {
|
||||
cacheFieldSet(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
throw "field '"
|
||||
+ name
|
||||
+ "' does not exist in custom class '"
|
||||
+ this.className
|
||||
+ "'"
|
||||
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// UNUSED
|
||||
public function __callGetter(name:String):Dynamic {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the real superClass if the Custom Class
|
||||
* extends another Custom Class, and so on until
|
||||
* it reaches a real class, otherwise it will
|
||||
* return the last fetched Custom Class
|
||||
* @return Null<Dynamic>
|
||||
*/
|
||||
public function getSuperclass():IHScriptCustomClassBehaviour {
|
||||
if(__superClass == null) return null;
|
||||
|
||||
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
|
||||
|
||||
// Check if the superClass is another custom class,
|
||||
// so it will find for a real class, otherwise
|
||||
// returns the last super CustomClass parent.
|
||||
while (cls != null && cls is CustomClass) {
|
||||
var next = cast(cls, CustomClass).__superClass;
|
||||
if (next == null)
|
||||
break; // Return the Custom Class itself
|
||||
cls = next;
|
||||
}
|
||||
return cls is CustomClass ? this : cls;
|
||||
}
|
||||
|
||||
// TODO: scripted safe cast for custom classes
|
||||
public function getUpperclass():IHScriptCustomClassBehaviour {
|
||||
if(__upperClass == null) return this;
|
||||
|
||||
var cls:CustomClass = cast __upperClass;
|
||||
|
||||
while (cls != null) {
|
||||
var prev:CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
|
||||
return cls;
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
return className;
|
||||
}
|
||||
+145
-111
@@ -1,115 +1,152 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.Interp.DeclaredVar;
|
||||
import hscript.utils.UnsafeReflect;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class CustomClassHandler implements IHScriptCustomConstructor {
|
||||
public static var staticHandler = new StaticHandler();
|
||||
|
||||
/**
|
||||
* Provides handlers for static custom class fields and instantiation.
|
||||
*/
|
||||
@:access(hscript.Property)
|
||||
class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{
|
||||
public var ogInterp:Interp;
|
||||
public var name:String;
|
||||
public var fields:Array<Expr>;
|
||||
public var extend:String;
|
||||
public var extend:Null<String>;
|
||||
public var interfaces:Array<String>;
|
||||
public final isFinal:Bool;
|
||||
|
||||
public var cl:Class<Dynamic>;
|
||||
public var cl:Dynamic;
|
||||
|
||||
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
|
||||
private var __interp:Interp;
|
||||
private var __staticFields:Array<String> = [];
|
||||
|
||||
public var __allowSetGet:Bool = true;
|
||||
|
||||
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>, ?isFinal:Bool) {
|
||||
this.ogInterp = ogInterp;
|
||||
this.name = name;
|
||||
this.fields = fields;
|
||||
this.extend = extend;
|
||||
this.interfaces = interfaces;
|
||||
this.isFinal = isFinal != null ? isFinal : false;
|
||||
|
||||
this.cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
|
||||
if(cl == null)
|
||||
ogInterp.error(EInvalidClass(extend));
|
||||
if(extend != null) {
|
||||
if(ogInterp.customClasses.exists(extend)) {
|
||||
var customCls:CustomClassHandler = ogInterp.customClasses.get(extend);
|
||||
if(customCls.isFinal)
|
||||
ogInterp.error(ECustom('Cannot extend a final class'));
|
||||
this.cl = customCls;
|
||||
}
|
||||
else
|
||||
this.cl = Type.resolveClass('${extend}_HSX');
|
||||
|
||||
if(cl == null)
|
||||
ogInterp.error(EInvalidClass(extend));
|
||||
}
|
||||
|
||||
initStatic();
|
||||
}
|
||||
|
||||
public function hnew(args:Array<Dynamic>):Dynamic {
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
throw "todo: do all this lmao -lunar";
|
||||
@:access(hscript.Interp)
|
||||
function initStatic() {
|
||||
__interp = new Interp();
|
||||
__interp.errorHandler = ogInterp.errorHandler;
|
||||
__interp.importFailedCallback = ogInterp.importFailedCallback;
|
||||
|
||||
//__interp.variables = ogInterp.variables;
|
||||
__interp.usingHandler.usingEntries = ogInterp.usingHandler.usingEntries;
|
||||
__interp.publicVariables = ogInterp.publicVariables;
|
||||
__interp.staticVariables = ogInterp.staticVariables;
|
||||
__interp.customClasses = ogInterp.customClasses;
|
||||
|
||||
for(f => v in ogInterp.variables)
|
||||
if(!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
|
||||
for(e in fields.copy()) {
|
||||
var validField:Bool = false;
|
||||
var staticField:Bool = false;
|
||||
var fieldName:String = "";
|
||||
switch (Tools.expr(e)) {
|
||||
case EVar(n, _, _, _, isStatic):
|
||||
validField = true;
|
||||
staticField = isStatic;
|
||||
fieldName = n;
|
||||
case EFunction(_, _, n, _, _, isStatic, _, _, _, _):
|
||||
validField = true;
|
||||
staticField = isStatic;
|
||||
fieldName = n;
|
||||
default:
|
||||
}
|
||||
|
||||
if(staticField && validField) {
|
||||
__interp.exprReturn(e);
|
||||
__staticFields.push(fieldName);
|
||||
fields.remove(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hnew(args:Array<Dynamic>):Dynamic
|
||||
return new CustomClass(this, args);
|
||||
|
||||
@:allow(hscript.Interp)
|
||||
function hasField(name:String) {
|
||||
return __staticFields.contains(name);
|
||||
}
|
||||
|
||||
function getField(name:String, allowProperty:Bool = true):Dynamic {
|
||||
var f = __interp.variables.get(name);
|
||||
if(f is Property && allowProperty) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callGetter(name);
|
||||
prop.__allowSetGet = null;
|
||||
return r;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
function setField(name:String, val:Dynamic):Dynamic {
|
||||
var f = getField(name, false);
|
||||
if(f is Property) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callSetter(name, val);
|
||||
prop.__allowSetGet = null;
|
||||
return r;
|
||||
}
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
if(name == 'new') {
|
||||
var __constructor = Reflect.makeVarArgs(function(args:Array<Dynamic>) {
|
||||
return this.hnew(args);
|
||||
});
|
||||
return __constructor;
|
||||
}
|
||||
|
||||
if(hasField(name)) {
|
||||
return getField(name);
|
||||
}
|
||||
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
||||
return null;
|
||||
#else
|
||||
var interp = new Interp();
|
||||
interp.errorHandler = ogInterp.errorHandler;
|
||||
}
|
||||
|
||||
var _class:IHScriptCustomClassBehaviour = Type.createInstance(cl, args);
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if(hasField(name))
|
||||
return setField(name, val);
|
||||
|
||||
var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
|
||||
var capturedLocals:Map<String, DeclaredVar> = [];
|
||||
for(k=>e in __capturedLocals)
|
||||
if (e != null && e.depth <= 0)
|
||||
capturedLocals.set(k, e);
|
||||
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
||||
return null;
|
||||
}
|
||||
|
||||
var disallowCopy = Type.getInstanceFields(cl);
|
||||
// UNUSED
|
||||
public function __callGetter(name:String):Dynamic {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (key => value in capturedLocals) {
|
||||
if(!disallowCopy.contains(key)) {
|
||||
interp.locals.set(key, {r: value, depth: -1});
|
||||
}
|
||||
}
|
||||
for (key => value in ogInterp.variables) {
|
||||
if(!disallowCopy.contains(key)) {
|
||||
interp.variables.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
var comparisonMap = new Map();
|
||||
for(key => value in interp.variables) {
|
||||
comparisonMap.set(key, value);
|
||||
}
|
||||
|
||||
_class.__custom__variables = interp.variables;
|
||||
|
||||
//trace(fields);
|
||||
|
||||
for(expr in fields) {
|
||||
@:privateAccess
|
||||
interp.exprReturn(expr);
|
||||
}
|
||||
|
||||
interp.variables.set("super", staticHandler);
|
||||
|
||||
_class.__interp = interp; // TODO: Remove
|
||||
interp.scriptObject = _class;
|
||||
// get only variables that were not set before
|
||||
var classVariables = [for(key => value in interp.variables) if(!comparisonMap.exists(key) || comparisonMap[key] != value) key => value];
|
||||
for(variable => value in classVariables) {
|
||||
if(variable == "this" || variable == "super") continue;
|
||||
@:privateAccess
|
||||
if(!interp.__instanceFields.contains(variable)) {
|
||||
interp.__instanceFields.push(variable);
|
||||
}
|
||||
}
|
||||
|
||||
//trace([for(key => value in classVariables) key]);
|
||||
//@:privateAccess
|
||||
//trace(interp.__instanceFields);
|
||||
|
||||
_class.__allowSetGet = false;
|
||||
|
||||
for(variable => value in interp.variables) {
|
||||
if(variable == "this") continue;
|
||||
|
||||
if(variable.startsWith("set_") || variable.startsWith("get_")) {
|
||||
_class.__allowSetGet = true;
|
||||
}
|
||||
}
|
||||
|
||||
var newFunc = interp.variables.get("new");
|
||||
if(newFunc != null) {
|
||||
UnsafeReflect.callMethodUnsafe(null, newFunc, args);
|
||||
}
|
||||
|
||||
var newFunc = interp.variables.get("new");
|
||||
if(newFunc != null) {
|
||||
UnsafeReflect.callMethodUnsafe(null, newFunc, args);
|
||||
}
|
||||
return _class;
|
||||
#end
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
@@ -117,44 +154,41 @@ class CustomClassHandler implements IHScriptCustomConstructor {
|
||||
}
|
||||
}
|
||||
|
||||
class TemplateClass implements IHScriptCustomClassBehaviour implements IHScriptCustomBehaviour {
|
||||
public var __interp:Interp; // TODO: Remove
|
||||
public var __custom__variables:Map<String, Dynamic>;
|
||||
|
||||
/**
|
||||
* This is for backwards compatibility with old hscript-improved, since some scripts use it
|
||||
**/
|
||||
@:dox(hide)
|
||||
@:keep
|
||||
class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustomAccessBehaviour {
|
||||
public var __interp:Interp;
|
||||
public var __allowSetGet:Bool = true;
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||
var variables = __interp.variables;
|
||||
if(__allowSetGet && variables.exists("set_" + name))
|
||||
return __callSetter(name, val);
|
||||
if (__custom__variables.exists(name)) {
|
||||
__custom__variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
UnsafeReflect.setProperty(this, name, val);
|
||||
return UnsafeReflect.field(this, name);
|
||||
variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
public function hget(name:String):Dynamic {
|
||||
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||
var variables = __interp.variables;
|
||||
if(__allowSetGet && variables.exists("get_" + name))
|
||||
return __callGetter(name);
|
||||
if (__custom__variables.exists(name))
|
||||
return __custom__variables.get(name);
|
||||
return UnsafeReflect.getProperty(this, name);
|
||||
return variables.get(name);
|
||||
}
|
||||
|
||||
public function __callGetter(name:String):Dynamic {
|
||||
__allowSetGet = false;
|
||||
var v = __custom__variables.get("get_" + name)();
|
||||
var v = __interp.variables.get("get_" + name)();
|
||||
__allowSetGet = true;
|
||||
return v;
|
||||
}
|
||||
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||
__allowSetGet = false;
|
||||
var v = __custom__variables.get("set_" + name)(val);
|
||||
var v = __interp.variables.get("set_" + name)(val);
|
||||
__allowSetGet = true;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
final class StaticHandler {
|
||||
public function new() {}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#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;
|
||||
EUnterminatedRegex;
|
||||
EInvalidPreprocessor( msg : String );
|
||||
EUnknownVariable( v : String );
|
||||
EInvalidIterator( v : String );
|
||||
EInvalidType( t : String );
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String, ?on : String );
|
||||
ECustom( msg : String );
|
||||
EPreset( msg : ErrorMessage );
|
||||
EInvalidClass( className : String);
|
||||
EAlreadyExistingClass( className : String);
|
||||
EInvalidEscape( s : String );
|
||||
}
|
||||
|
||||
enum abstract ErrorMessage(Expr.UInt8) from Expr.UInt8 to Expr.UInt8 {
|
||||
final INVALID_CHAR_CODE_MULTI;
|
||||
final FROM_CHAR_CODE_NON_INT;
|
||||
final EMPTY_INTERPOLATION;
|
||||
final UNKNOWN_MAP_TYPE;
|
||||
final UNKNOWN_MAP_TYPE_RUNTIME;
|
||||
final EXPECT_KEY_VALUE_SYNTAX;
|
||||
|
||||
public function toString():String {
|
||||
return switch(cast this) {
|
||||
case INVALID_CHAR_CODE_MULTI: "'char'.code only works on single characters";
|
||||
case FROM_CHAR_CODE_NON_INT: "String.fromCharCode only works on integers";
|
||||
case EMPTY_INTERPOLATION: "Invalid interpolation: Expression cannot be empty";
|
||||
case UNKNOWN_MAP_TYPE: "Unknown Map Type";
|
||||
case UNKNOWN_MAP_TYPE_RUNTIME: "Unknown Map Type, while parsing at runtime";
|
||||
case EXPECT_KEY_VALUE_SYNTAX: "Expected a => b";
|
||||
}
|
||||
}
|
||||
}
|
||||
+138
-291
@@ -21,43 +21,129 @@
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
typedef Int8 = #if cpp cpp.Int8 #else Int #end;
|
||||
typedef Int16 = #if cpp cpp.Int16 #else Int #end;
|
||||
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||
typedef Int64 = #if cpp cpp.Int64 #else Int #end;
|
||||
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||
|
||||
typedef UInt8 = #if cpp cpp.UInt8 #else Int #end;
|
||||
typedef UInt16 = #if cpp cpp.UInt16 #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 !haxe3
|
||||
CInt32( v : haxe.Int32 );
|
||||
#end
|
||||
CString( s : String, ?i : Bool );
|
||||
}
|
||||
|
||||
enum abstract MapType(UInt8) {
|
||||
var Null;
|
||||
var IntMap;
|
||||
var StringMap;
|
||||
var EnumMap;
|
||||
var ObjectMap;
|
||||
var UnknownMap;
|
||||
}
|
||||
|
||||
typedef Error = hscript.Error.Error_;
|
||||
|
||||
#if hscriptPos
|
||||
class Expr {
|
||||
@: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 );
|
||||
|
||||
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>;
|
||||
}
|
||||
|
||||
@: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;
|
||||
@@ -65,271 +151,28 @@ class Expr {
|
||||
this.origin = origin;
|
||||
this.line = line;
|
||||
}
|
||||
public function toString(): String {
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ExprDef
|
||||
enum ErrorDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr
|
||||
enum Error {
|
||||
#end
|
||||
{
|
||||
EConst( c : Const );
|
||||
EIdent( v : VarN );
|
||||
EVar( n : VarN, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool );
|
||||
EParent( e : Expr, ?noOptimize : Bool );
|
||||
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 : VarN, it : Expr, e : Expr);
|
||||
EForKeyValue( v : VarN, it : Expr, e : Expr, ithv: VarN);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : VarN, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EMapDecl( type: MapType, keys: Array<Expr>, values: Array<Expr> );
|
||||
EArrayDecl( e : Array<Expr> );
|
||||
ENew( cl : VarN, params : Array<Expr> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : VarN, 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, mode: KImportMode );
|
||||
EClass( name:VarN, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
|
||||
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
EInfo( info: InfoClass, e: Expr );
|
||||
#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 Binop {
|
||||
/**
|
||||
`+`
|
||||
**/
|
||||
OpAdd;
|
||||
|
||||
/**
|
||||
`*`
|
||||
**/
|
||||
OpMult;
|
||||
|
||||
/**
|
||||
`/`
|
||||
**/
|
||||
OpDiv;
|
||||
|
||||
/**
|
||||
`-`
|
||||
**/
|
||||
OpSub;
|
||||
|
||||
/**
|
||||
`=`
|
||||
**/
|
||||
OpAssign;
|
||||
|
||||
/**
|
||||
`==`
|
||||
**/
|
||||
OpEq;
|
||||
|
||||
/**
|
||||
`!=`
|
||||
**/
|
||||
OpNotEq;
|
||||
|
||||
/**
|
||||
`>`
|
||||
**/
|
||||
OpGt;
|
||||
|
||||
/**
|
||||
`>=`
|
||||
**/
|
||||
OpGte;
|
||||
|
||||
/**
|
||||
`<`
|
||||
**/
|
||||
OpLt;
|
||||
|
||||
/**
|
||||
`<=`
|
||||
**/
|
||||
OpLte;
|
||||
|
||||
/**
|
||||
`&`
|
||||
**/
|
||||
OpAnd;
|
||||
|
||||
/**
|
||||
`|`
|
||||
**/
|
||||
OpOr;
|
||||
|
||||
/**
|
||||
`^`
|
||||
**/
|
||||
OpXor;
|
||||
|
||||
/**
|
||||
`&&`
|
||||
**/
|
||||
OpBoolAnd;
|
||||
|
||||
/**
|
||||
`||`
|
||||
**/
|
||||
OpBoolOr;
|
||||
|
||||
/**
|
||||
`<<`
|
||||
**/
|
||||
OpShl;
|
||||
|
||||
/**
|
||||
`>>`
|
||||
**/
|
||||
OpShr;
|
||||
|
||||
/**
|
||||
`>>>`
|
||||
**/
|
||||
OpUShr;
|
||||
|
||||
/**
|
||||
`%`
|
||||
**/
|
||||
OpMod;
|
||||
|
||||
/**
|
||||
`+=` `-=` `/=` `*=` `<<=` `>>=` `>>>=` `|=` `&=` `^=` `%=`
|
||||
**/
|
||||
OpAssignOp(op:Binop);
|
||||
|
||||
/**
|
||||
`...`
|
||||
**/
|
||||
OpInterval;
|
||||
|
||||
/**
|
||||
`=>`
|
||||
**/
|
||||
OpArrow;
|
||||
|
||||
/**
|
||||
`is`
|
||||
**/
|
||||
OpIs; // used to be OpIn, but our system treats that differently
|
||||
|
||||
/**
|
||||
`??`
|
||||
**/
|
||||
OpNullCoal;
|
||||
}
|
||||
|
||||
enum abstract Unop(UInt8) {
|
||||
/**
|
||||
`++`
|
||||
**/
|
||||
var OpIncrement;
|
||||
|
||||
/**
|
||||
`--`
|
||||
**/
|
||||
var OpDecrement;
|
||||
|
||||
/**
|
||||
`!`
|
||||
**/
|
||||
var OpNot;
|
||||
|
||||
/**
|
||||
`-`
|
||||
**/
|
||||
var OpNeg;
|
||||
|
||||
/**
|
||||
`~`
|
||||
**/
|
||||
var OpNegBits;
|
||||
|
||||
/**
|
||||
`...`
|
||||
**/
|
||||
var OpSpread;
|
||||
}
|
||||
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
class InfoClass {
|
||||
public var variables:Array<String>;
|
||||
|
||||
public function new(variables:Array<String>) {
|
||||
this.variables = variables;
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
enum KImportMode {
|
||||
INormal;
|
||||
IAs( name : String );
|
||||
IAsReturn;
|
||||
IAll;
|
||||
}
|
||||
|
||||
class ObjectField {
|
||||
public var name:String;
|
||||
public var e:Expr;
|
||||
|
||||
public function new(name, e) {
|
||||
this.name = name;
|
||||
this.e = e;
|
||||
}
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class SwitchCase {
|
||||
public var values : Array<Expr>;
|
||||
public var expr : Expr;
|
||||
}
|
||||
|
||||
//typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||
class Argument {
|
||||
public var name : VarN;
|
||||
public var t : Null<CType>;
|
||||
public var opt : Bool;
|
||||
public var value : Null<Expr>;
|
||||
public function new(name, ?t, ?opt, ?value) {
|
||||
this.name = name;
|
||||
this.t = t;
|
||||
this.opt = opt;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public function toString() {
|
||||
return (opt ? "?" : "") + name + (t != null ? ":" + Printer.convertTypeToString(t) : "") + (value != null ? "=" + Printer.convertExprToString(value) : "");
|
||||
}
|
||||
}
|
||||
|
||||
typedef Metadata = Array<{ name : String, params : Array<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 );
|
||||
}
|
||||
|
||||
enum ModuleDecl {
|
||||
DPackage( path : Array<String> );
|
||||
@@ -372,15 +215,25 @@ enum abstract FieldAccess(UInt8) {
|
||||
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 );
|
||||
}
|
||||
|
||||
typedef FunctionDecl = {
|
||||
var args : Array<Argument>;
|
||||
var expr : Expr;
|
||||
var ret : Null<CType>;
|
||||
@:structInit
|
||||
final class FunctionDecl {
|
||||
public var args : Array<Argument>;
|
||||
public var body : Expr;
|
||||
public var ret : Null<CType>;
|
||||
}
|
||||
|
||||
typedef VarDecl = {
|
||||
@@ -389,9 +242,3 @@ typedef VarDecl = {
|
||||
var expr : Null<Expr>;
|
||||
var type : Null<CType>;
|
||||
}
|
||||
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
abstract VarN(Dynamic) from Int from String to Int to String {}
|
||||
#else
|
||||
typedef VarN = String;
|
||||
#end
|
||||
@@ -0,0 +1,66 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.utils.UnsafeReflect;
|
||||
|
||||
// TODO: EnumTools for scripted enums
|
||||
/**
|
||||
* Wrapper class for enums, both for real and scripted.
|
||||
*/
|
||||
@:structInit
|
||||
class HEnum implements IHScriptCustomBehaviour {
|
||||
private var enumValues(default, null) = {};
|
||||
|
||||
public function setEnum(name:String, enumValue:Dynamic):Void {
|
||||
UnsafeReflect.setField(enumValues, name, enumValue);
|
||||
}
|
||||
|
||||
public function getEnum(name:String):Null<Dynamic> {
|
||||
if (UnsafeReflect.hasField(enumValues, name))
|
||||
return UnsafeReflect.field(enumValues, name);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
return getEnum(name);
|
||||
}
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@:nullSafety
|
||||
@:structInit
|
||||
class HEnumValue {
|
||||
public var enumName:String;
|
||||
public var fieldName:String;
|
||||
public var index:Int;
|
||||
public var args:Array<Dynamic>;
|
||||
|
||||
public function toString():String {
|
||||
return '$enumName.$fieldName${args.length > 0 ? '(${[for (a in args) a].join(", ")})' : ''}';
|
||||
}
|
||||
|
||||
public inline function getEnumName():String
|
||||
return this.enumName;
|
||||
|
||||
public inline function getConstructorArgs():Array<Dynamic>
|
||||
return this.args;
|
||||
|
||||
public function compare(other:HEnumValue):Bool {
|
||||
if (enumName != other.enumName || fieldName != other.fieldName)
|
||||
return false;
|
||||
if (args.length == 0 && other.args.length == 0)
|
||||
return true;
|
||||
if (args.length == 0 || other.args.length == 0)
|
||||
return false;
|
||||
if (args.length != other.args.length)
|
||||
return false;
|
||||
|
||||
for (i in 0...args.length) // TODO: allow deep comparison, like arrays
|
||||
if (args[i] != other.args[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package hscript;
|
||||
|
||||
// Soon...
|
||||
interface IHScriptAbstractBehaviour extends IHScriptCustomBehaviour {
|
||||
public var hasOp:Bool;
|
||||
public var hasArr:Bool;
|
||||
// @:op(A * B), @:op(A++), etc...
|
||||
public function hop(kind:String, a:Dynamic, ?b:Dynamic):Dynamic;
|
||||
|
||||
public function harrayget(key:Dynamic):Dynamic;
|
||||
public function harrayset(key:Dynamic, val:Dynamic):Dynamic;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package hscript;
|
||||
|
||||
/**
|
||||
* Same Interface as IHScriptCustomBehaviour but for Property.
|
||||
*/
|
||||
interface IHScriptCustomAccessBehaviour extends IHScriptCustomBehaviour {
|
||||
var __allowSetGet:Bool;
|
||||
|
||||
public function __callGetter(name:String):Dynamic;
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
||||
}
|
||||
@@ -1,6 +1,23 @@
|
||||
package hscript;
|
||||
|
||||
/**
|
||||
* Special Interface for handling field access behaviour.
|
||||
* Basically works like the operator overload `@:op(a.b)`
|
||||
* for an abstract.
|
||||
*/
|
||||
interface IHScriptCustomBehaviour {
|
||||
/**
|
||||
* Field Write Access
|
||||
* @param name - Field Name
|
||||
* @param val - Value to assign
|
||||
* @return Dynamic - The assigned value
|
||||
*/
|
||||
public function hset(name:String, val:Dynamic):Dynamic;
|
||||
|
||||
/**
|
||||
* Field Read Access
|
||||
* @param name - Field Name
|
||||
* @return Dynamic - The returned field
|
||||
*/
|
||||
public function hget(name:String):Dynamic;
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.Interp;
|
||||
/**
|
||||
* Special Interface to make a class usable for Custom Classes.
|
||||
*/
|
||||
interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{
|
||||
public var __interp:Interp;
|
||||
public var __real_fields:Array<String>;
|
||||
public var __class__fields:Array<String>;
|
||||
|
||||
interface IHScriptCustomClassBehaviour {
|
||||
public var __interp:Interp; // TODO: Remove
|
||||
public var __custom__variables:Map<String, Dynamic>;
|
||||
public var __allowSetGet:Bool;
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic;
|
||||
public function hget(name:String):Dynamic;
|
||||
|
||||
public function __callGetter(name:String):Dynamic;
|
||||
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package hscript;
|
||||
|
||||
/**
|
||||
* Special Interface for handling new instances of an object.
|
||||
*/
|
||||
interface IHScriptCustomConstructor {
|
||||
public function hnew(args:Array<Dynamic>):Dynamic;
|
||||
}
|
||||
+869
-873
File diff suppressed because it is too large
Load Diff
+8
-56
@@ -29,23 +29,13 @@ import haxe.macro.Expr;
|
||||
class Macro {
|
||||
|
||||
var p : Position;
|
||||
#if haxe3
|
||||
var binops : Map<String,Binop>;
|
||||
var unops : Map<String,Unop>;
|
||||
#else
|
||||
var binops : Hash<Binop>;
|
||||
var unops : Hash<Unop>;
|
||||
#end
|
||||
|
||||
public function new(pos) {
|
||||
p = pos;
|
||||
#if haxe3
|
||||
binops = new Map();
|
||||
unops = new Map();
|
||||
#else
|
||||
binops = new Hash();
|
||||
unops = new Hash();
|
||||
#end
|
||||
for( c in Type.getEnumConstructs(Binop) ) {
|
||||
if( c == "OpAssignOp" ) continue;
|
||||
var op = Type.createEnum(Binop, c);
|
||||
@@ -73,9 +63,7 @@ class Macro {
|
||||
case OpMod: assign = true; "%";
|
||||
case OpAssignOp(_): "";
|
||||
case OpInterval: "...";
|
||||
#if haxe3
|
||||
case OpArrow: "=>";
|
||||
#end
|
||||
#if (haxe_ver >= 4)
|
||||
case OpIn: "in";
|
||||
#end
|
||||
@@ -102,15 +90,8 @@ class Macro {
|
||||
}
|
||||
}
|
||||
|
||||
#if !haxe3
|
||||
function isType(v:String) {
|
||||
var c0 = v.charCodeAt(0);
|
||||
return c0 >= 'A'.code && c0 <= 'Z'.code;
|
||||
}
|
||||
#end
|
||||
|
||||
function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> {
|
||||
var b = new Array();
|
||||
var b = [];
|
||||
for( x in a )
|
||||
b.push(f(x));
|
||||
return b;
|
||||
@@ -146,6 +127,8 @@ class Macro {
|
||||
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
|
||||
}
|
||||
TAnonymous(tf);
|
||||
case CTExpr(_):
|
||||
throw "assert";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -156,17 +139,9 @@ class Macro {
|
||||
case CInt(v): CInt(Std.string(v));
|
||||
case CFloat(f): CFloat(Std.string(f));
|
||||
case CString(s): CString(s);
|
||||
#if !haxe3
|
||||
case CInt32(v): CInt(Std.string(v));
|
||||
#end
|
||||
});
|
||||
case EIdent(v):
|
||||
#if !haxe3
|
||||
if( isType(v) )
|
||||
EConst(CType(v));
|
||||
else
|
||||
#end
|
||||
EConst(CIdent(v));
|
||||
EConst(CIdent(v));
|
||||
case EVar(n, t, e):
|
||||
EVars([ { name : n, expr : if( e == null ) null else convert(e), type : if( t == null ) null else convertType(t) } ]);
|
||||
case EParent(e):
|
||||
@@ -174,12 +149,7 @@ class Macro {
|
||||
case EBlock(el):
|
||||
EBlock(map(el,convert));
|
||||
case EField(e, f):
|
||||
#if !haxe3
|
||||
if( isType(f) )
|
||||
EType(convert(e), f);
|
||||
else
|
||||
#end
|
||||
EField(convert(e), f);
|
||||
EField(convert(e), f);
|
||||
case EBinop(op, e1, e2):
|
||||
var b = binops.get(op);
|
||||
if( b == null ) throw EInvalidOp(op);
|
||||
@@ -198,23 +168,11 @@ class Macro {
|
||||
EWhile(convert(c), convert(e), false);
|
||||
case EFor(v, it, efor):
|
||||
#if (haxe_ver >= 4)
|
||||
var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||
#elseif (haxe_211 || haxe3)
|
||||
var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
#else
|
||||
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||
#else
|
||||
EFor(v, convert(it), convert(efor));
|
||||
#end
|
||||
case EForKeyValue(v, it, efor, ithv):
|
||||
#if (haxe_ver >= 4)
|
||||
var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor), ithv);
|
||||
#elseif (haxe_211 || haxe3)
|
||||
var p:Expr = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor), ithv);
|
||||
#else
|
||||
EFor(v, convert(it), convert(efor), ithv);
|
||||
#end
|
||||
case EBreak:
|
||||
EBreak;
|
||||
@@ -239,12 +197,6 @@ class Macro {
|
||||
EReturn(e == null ? null : convert(e));
|
||||
case EArray(e, index):
|
||||
EArray(convert(e), convert(index));
|
||||
case EMapDecl(type, keys, values): // port to array decl, haxe still uses EArrayDecl but with => as a binop
|
||||
var el = [];
|
||||
for( i in 0...keys.length ) {
|
||||
el.push( hscript.Expr.EBinop("=>", keys[i], values[i]) );
|
||||
}
|
||||
EArrayDecl(map(el,convert));
|
||||
case EArrayDecl(el):
|
||||
EArrayDecl(map(el,convert));
|
||||
case ENew(cl, params):
|
||||
|
||||
@@ -1,643 +0,0 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.Expr;
|
||||
import hscript.Tools;
|
||||
import hscript.Parser;
|
||||
|
||||
@:access(hscript.Parser)
|
||||
class Optimizer {
|
||||
static inline function expr(e:Expr) return Tools.expr(e);
|
||||
|
||||
public static function optimize(s:Expr):Expr {
|
||||
if(s == null)
|
||||
return null;
|
||||
|
||||
var e = Tools.expr(s);
|
||||
|
||||
// TODO: Convert EBinOp(+, a, EUnop(-, b)) to EBinOp(-, a, b) aka (a - b)
|
||||
// TODO: Make it so if EFor & EForKeyValue iterator variable isnt used its replaced with a $, which the code handles as doesnt exist
|
||||
// TODO: Make it so <PURE_VAR|CONST> == ?; gets removed, IF it isnt stored
|
||||
// TODO: Optimize ?. and ??
|
||||
// TODO: Optimize Std.string(CONSTANT) to "CONSTANT"
|
||||
// TODO: Remove Std.string if its the right side of a binop of a string
|
||||
// TODO: Add EForComprehension, EWhileComprehension, EDoWhileComprehension for better optimization
|
||||
// TODO: Optimize EFor(v, it, EBlock([e1])) to EFor(v, it, e1)
|
||||
// TODO: Optimize EIf(cond, e1, e2) to EBlock([cond, e1]) if e1 == e2, if cond is constant or side effect free then convert to EParent(e1)
|
||||
|
||||
switch(e) {
|
||||
// Parse all expressions and recreate the AST
|
||||
case EBlock(exprs):
|
||||
var exprs = exprs.map((v) -> optimize(v)).filter((v) -> v != null).filter((v) -> {
|
||||
if(Tools.expr(v).match(EBlock([]))) return false; // Remove empty blocks
|
||||
return true;
|
||||
});
|
||||
|
||||
var newExprs = [];
|
||||
for(e in exprs) {
|
||||
switch(Tools.expr(e)) {
|
||||
case EBlock(iex):
|
||||
var declares = Lambda.exists(iex, ie -> hasDecl(ie));
|
||||
if(!declares) {
|
||||
for(ex in iex)
|
||||
newExprs.push(ex);
|
||||
} else {
|
||||
newExprs.push(e);
|
||||
}
|
||||
case EReturn(_): // remove stuff that are after a return
|
||||
newExprs.push(e);
|
||||
break;
|
||||
default:
|
||||
newExprs.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
return mk(EBlock(newExprs), s);
|
||||
|
||||
case EIf(econd, e1, e2):
|
||||
var econd = optimize(econd);
|
||||
var e1 = optimize(e1);
|
||||
var e2 = optimize(e2);
|
||||
if(isBool(econd)) {
|
||||
var econd = getBool(econd);
|
||||
if(econd == true) {
|
||||
if(e1 == null)
|
||||
return mk(EBlock([]), s);
|
||||
return mk(EBlock([e1]), s);
|
||||
} else {
|
||||
if(e2 == null)
|
||||
return mk(EBlock([]), s);
|
||||
return mk(EBlock([e2]), s);
|
||||
}
|
||||
}
|
||||
if(e2 != null && isBool(e1) && isBool(e2)) {
|
||||
var c1 = getBool(e1);
|
||||
var c2 = getBool(e2);
|
||||
|
||||
if(c1 == false && c2 == true) { // (VAR ? false : true)
|
||||
return optimize(mk(EUnop(OpNot, true, econd), s));
|
||||
}
|
||||
if(c1 == true && c2 == false) { // (VAR ? true : false)
|
||||
return optimize(mk(Tools.expr(econd), s));
|
||||
}
|
||||
if(isConstant(econd)) { // Side effect free
|
||||
if(c1 == true && c2 == true) { // (CONST ? true : true)
|
||||
return mk(convertConstant(true), s);
|
||||
}
|
||||
if(c1 == false && c2 == false) { // (CONST ? false : false)
|
||||
return mk(convertConstant(false), s);
|
||||
}
|
||||
// TODO: Check if local variables are used in the condition
|
||||
// Since they cant have side effects, they can be optimized
|
||||
}
|
||||
}
|
||||
return mk(EIf(econd, e1, e2), s);
|
||||
|
||||
case ETernary(econd, e1, e2):
|
||||
var econd = optimize(econd);
|
||||
var e1 = optimize(e1);
|
||||
var e2 = optimize(e2);
|
||||
if(isConstant(econd)) {
|
||||
var econd = getConstant(econd);
|
||||
if(econd == true) {
|
||||
if(e1 == null)
|
||||
return mk(EBlock([]), s);
|
||||
return mk(EParent(e1), s);
|
||||
} else {
|
||||
if(e2 == null)
|
||||
return mk(EBlock([]), s);
|
||||
return mk(EParent(e2), s);
|
||||
}
|
||||
}
|
||||
if(isBool(e1) && isBool(e2)) {
|
||||
var c1 = getBool(e1);
|
||||
var c2 = getBool(e2);
|
||||
|
||||
if(c1 == false && c2 == true) { // (VAR ? false : true)
|
||||
return optimize(mk(EUnop(OpNot, true, econd), s));
|
||||
}
|
||||
if(c1 == true && c2 == false) { // (VAR ? true : false)
|
||||
return optimize(mk(Tools.expr(econd), s));
|
||||
}
|
||||
if(isConstant(econd)) { // Side effect free
|
||||
if(c1 == true && c2 == true) { // (CONST ? true : true)
|
||||
return mk(convertConstant(true), s);
|
||||
}
|
||||
if(c1 == false && c2 == false) { // (CONST ? false : false)
|
||||
return mk(convertConstant(false), s);
|
||||
}
|
||||
// TODO: Check if local variables are used in the condition
|
||||
// Since they cant have side effects, they can be optimized
|
||||
}
|
||||
}
|
||||
return mk(ETernary(econd, e1, e2), s);
|
||||
case EWhile(econd, e):
|
||||
var econd = optimize(econd);
|
||||
var e = optimize(e);
|
||||
return mk(EWhile(econd, e), s);
|
||||
case EDoWhile(econd, e):
|
||||
var econd = optimize(econd);
|
||||
var e = optimize(e);
|
||||
return mk(EDoWhile(econd, e), s);
|
||||
case EFor(v, it, e):
|
||||
var it = optimize(it);
|
||||
var e = optimize(e);
|
||||
return mk(EFor(v, it, e), s);
|
||||
case EForKeyValue(v, it, e, ithv):
|
||||
var it = optimize(it);
|
||||
var e = optimize(e);
|
||||
return mk(EForKeyValue(v, it, e, ithv), s);
|
||||
case EBreak:
|
||||
return mk(EBreak, s);
|
||||
case EContinue:
|
||||
return mk(EContinue, s);
|
||||
case EReturn(e):
|
||||
var e = optimize(e);
|
||||
return mk(EReturn(e), s);
|
||||
|
||||
case ETry(e, v, t, ecatch):
|
||||
var e = optimize(e);
|
||||
var ecatch = optimize(ecatch);
|
||||
return mk(ETry(e, v, t, ecatch), s);
|
||||
|
||||
case EThrow(e):
|
||||
var e = optimize(e);
|
||||
return mk(EThrow(e), s);
|
||||
|
||||
case EVar(n, t, e, isPublic, isStatic):
|
||||
e = optimize(e);
|
||||
return mk(EVar(n, t, e, isPublic, isStatic), s);
|
||||
|
||||
case ECall(e, params):
|
||||
e = optimize(e);
|
||||
params = params.map((v) -> optimize(v));
|
||||
|
||||
function p(i:Int, t:ConstType, opt:Bool = false):Dynamic {
|
||||
var p = params[i];
|
||||
if(t != getConstType(p))
|
||||
if(opt)
|
||||
return null;
|
||||
else
|
||||
throw Parser.getBaseError(EInvalidType(getTypeName(p)));
|
||||
return switch(t) {
|
||||
case CTInt: getInt(p);
|
||||
case CTFloat: getFloat(p);
|
||||
case CTBool: getBool(p);
|
||||
case CTString: getStringConstant(p);
|
||||
case CTNull: null;
|
||||
}
|
||||
}
|
||||
|
||||
switch(Tools.expr(e)) {
|
||||
case EField(expr(_) => EConst(CString(str)), field):
|
||||
switch(field) {
|
||||
case "toString":
|
||||
if(params.length != 0) throw Parser.getBaseError(ECustom("String.toString() takes no arguments"));
|
||||
return mk(convertConstant(str.toString()), s);
|
||||
|
||||
case "toUpperCase":
|
||||
if(params.length != 0) throw Parser.getBaseError(ECustom("String.toUpperCase() takes no arguments"));
|
||||
return mk(convertConstant(str.toUpperCase()), s);
|
||||
|
||||
case "toLowerCase":
|
||||
if(params.length != 0) throw Parser.getBaseError(ECustom("String.toLowerCase() takes no arguments"));
|
||||
return mk(convertConstant(str.toLowerCase()), s);
|
||||
|
||||
case "charAt":
|
||||
var index = p(0, CTInt);
|
||||
return mk(convertConstant(str.charAt(index)), s);
|
||||
|
||||
case "charCodeAt":
|
||||
var index = p(0, CTInt);
|
||||
return mk(convertConstant(str.charCodeAt(index)), s);
|
||||
|
||||
case "indexOf":
|
||||
var value = p(0, CTString);
|
||||
var startIndex = p(1, CTInt, true);
|
||||
return mk(convertConstant(str.indexOf(value, startIndex)), s);
|
||||
|
||||
case "lastIndexOf":
|
||||
var value = p(0, CTString);
|
||||
var startIndex = p(1, CTInt, true);
|
||||
return mk(convertConstant(str.lastIndexOf(value, startIndex)), s);
|
||||
|
||||
case "split":
|
||||
var delimiter = p(0, CTString);
|
||||
var strArr = str == "" ? [] : str.split(delimiter); // fix platform dependent behavior
|
||||
return mk(EArrayDecl([for(st in strArr) mk(EConst(CString(st)), s)]), s);
|
||||
|
||||
case "substr":
|
||||
var pos = p(0, CTInt);
|
||||
var len = p(1, CTInt, true);
|
||||
return mk(convertConstant(str.substr(pos, len)), s);
|
||||
|
||||
case "substring":
|
||||
var startIndex = p(0, CTInt);
|
||||
var endIndex = p(1, CTInt, true);
|
||||
return mk(convertConstant(str.substring(startIndex, endIndex)), s);
|
||||
}
|
||||
default:
|
||||
}
|
||||
switch(Tools.expr(e)) {
|
||||
|
||||
default:
|
||||
}
|
||||
return mk(ECall(e, params), s);
|
||||
|
||||
case EField(e, f, safe):
|
||||
e = optimize(e);
|
||||
switch(Tools.expr(e)) {
|
||||
case EConst(CString(str)) if(f == "length"):
|
||||
return mk(convertConstant(str.length), s);
|
||||
default:
|
||||
}
|
||||
return mk(EField(e, f, safe), s);
|
||||
|
||||
case EIdent(_) | EConst(_):
|
||||
return s;
|
||||
|
||||
case EParent(e, noOptimize):
|
||||
e = optimize(e);
|
||||
return mk(noOptimize ? EParent(e) : Tools.expr(e), s);
|
||||
|
||||
case ECheckType(e, t):
|
||||
e = optimize(e);
|
||||
return mk(ECheckType(e, t), s);
|
||||
|
||||
case EMeta(name, args, e):
|
||||
e = optimize(e);
|
||||
return mk(EMeta(name, args, e), s);
|
||||
|
||||
case ENew(cl, args):
|
||||
args = args.map((v) -> optimize(v));
|
||||
return mk(ENew(cl, args), s);
|
||||
|
||||
case EObject(fl):
|
||||
fl.map((v) -> {
|
||||
v.e = optimize(v.e);
|
||||
});
|
||||
return mk(EObject(fl), s);
|
||||
|
||||
case EImport(c, n):
|
||||
return mk(EImport(c, n), s);
|
||||
|
||||
case EClass(name, fields, extend, interfaces): // Possible code not working
|
||||
fields = fields.map((v) -> optimize(v));
|
||||
return mk(EClass(name, fields, extend, interfaces), s);
|
||||
|
||||
case EFunction(args, e, name, ret, isPublic, isStatic, isOverride):
|
||||
args.map((v) -> {
|
||||
v.name = v.name;
|
||||
v.value = optimize(v.value);
|
||||
});
|
||||
e = optimize(e);
|
||||
return mk(EFunction(args, e, name, ret, isPublic, isStatic, isOverride), s);
|
||||
|
||||
case ESwitch(e, cases, def):
|
||||
e = optimize(e);
|
||||
cases.map((v) -> {
|
||||
var values = v.values.map((v) -> optimize(v));
|
||||
v.expr = optimize(v.expr);
|
||||
});
|
||||
def = optimize(def);
|
||||
|
||||
if(isConstant(e)) {
|
||||
var econd = getConstant(e);
|
||||
|
||||
for(c in cases) {
|
||||
for(v in c.values) {
|
||||
if(isConstant(v)) {
|
||||
var value = getConstant(v);
|
||||
if(value == econd)
|
||||
return mk(Tools.expr(c.expr), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maybe convert this to a Lambda.foreach?
|
||||
var isAllCasesConstant = true;
|
||||
for(c in cases) {
|
||||
for(v in c.values) {
|
||||
if(!isConstant(v)) {
|
||||
isAllCasesConstant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isAllCasesConstant) {
|
||||
#if debug
|
||||
//trace("Didnt find any cases that match");
|
||||
#end
|
||||
if(def != null)
|
||||
return mk(Tools.expr(def), s);
|
||||
else
|
||||
return mk(EBlock([]), s);
|
||||
}
|
||||
}
|
||||
|
||||
return mk(ESwitch(e, cases, def), s);
|
||||
|
||||
case EMapDecl(type, keys, values):
|
||||
keys = keys.map((v) -> optimize(v));
|
||||
values = values.map((v) -> optimize(v));
|
||||
return mk(EMapDecl(type, keys, values), s);
|
||||
|
||||
case EArrayDecl(arr):
|
||||
arr = arr.map((v) -> optimize(v));
|
||||
return mk(EArrayDecl(arr), s);
|
||||
|
||||
case EArray(e, index):
|
||||
e = optimize(e);
|
||||
index = optimize(index);
|
||||
if(isConstant(index)) {
|
||||
if(Tools.expr(e).match(EArrayDecl(_))) {
|
||||
var arr = switch(Tools.expr(e)) {
|
||||
case EArrayDecl(arr): arr;
|
||||
default: null;
|
||||
};
|
||||
|
||||
var constant = Lambda.exists(arr, isConstant);
|
||||
var index = getInt(index);
|
||||
if(constant && index != null) {
|
||||
return mk(Tools.expr(arr[index]), s);
|
||||
}
|
||||
}
|
||||
if(Tools.expr(e).match(EMapDecl(_))) {
|
||||
var map = switch(Tools.expr(e)) {
|
||||
case EMapDecl(type, keys, vals): [for(i in 0...keys.length) [keys[i], vals[i]]];
|
||||
default: null;
|
||||
};
|
||||
|
||||
var constant = Lambda.exists(map, (v) -> isConstant(v[0]) && isConstant(v[1]));
|
||||
if(constant) {
|
||||
var idx = Lambda.findIndex(map, (v) -> Type.enumEq(Tools.expr(v[0]), Tools.expr(index)));
|
||||
if(idx == -1)
|
||||
return mk(EIdent("null"), s);
|
||||
return mk(Tools.expr(map[idx][1]), s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mk(EArray(e, index), s);
|
||||
|
||||
case EBinop(op, e1, e2):
|
||||
e1 = optimize(e1);
|
||||
e2 = optimize(e2);
|
||||
|
||||
if(isConstant(e1) && isConstant(e2)) {
|
||||
var optimized:Dynamic = optimizeOp(op, getConstant(e1), getConstant(e2));
|
||||
if(optimized != null)
|
||||
return mk(convertConstant(optimized), s);
|
||||
}
|
||||
|
||||
// Possible bugs here
|
||||
if(isNumber(e1) && !isConstant(e2)) {
|
||||
var c1 = getNumber(e1);
|
||||
if(compareNumber(c1, 0) && op == OpAdd)
|
||||
return mk(Tools.expr(e2), s);
|
||||
if(compareNumber(c1, 1) && op == OpMult)
|
||||
return mk(Tools.expr(e2), s);
|
||||
//if(compareNumber(c1, 0) && op == "*")
|
||||
// return mk(convertConstant(0), s);
|
||||
}
|
||||
|
||||
if(!isConstant(e1) && isNumber(e2)) {
|
||||
var c2 = getNumber(e2);
|
||||
if(op == OpAdd && compareNumber(c2, 0))
|
||||
return mk(Tools.expr(e1), s);
|
||||
if(op == OpDiv && compareNumber(c2, 1))
|
||||
return mk(Tools.expr(e1), s);
|
||||
if(op == OpMult && compareNumber(c2, 1))
|
||||
return mk(Tools.expr(e1), s);
|
||||
//if(op == "*" && compareNumber(c2, 0))
|
||||
// return mk(convertConstant(0), s);
|
||||
}
|
||||
|
||||
return mk(EBinop(op, e1, e2), s);
|
||||
|
||||
case EUnop(op, prefix, e):
|
||||
e = optimize(e);
|
||||
|
||||
if(isConstant(e) && prefix) {
|
||||
var constant:Dynamic = getConstant(e);
|
||||
switch(op) {
|
||||
case OpNeg: return mk(convertConstant(-constant), s);
|
||||
case OpNot: return mk(convertConstant(!constant), s);
|
||||
case OpNegBits:
|
||||
var complement = #if (neko && !haxe3) haxe.Int32.complement(constant) #else ~constant #end;
|
||||
return mk(convertConstant(complement), s);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
return mk(EUnop(op, prefix, e), s);
|
||||
default:
|
||||
Sys.println("Unknown expr: " + e);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static function compareNumber(a:Dynamic, b:Dynamic):Bool {
|
||||
return switch(Type.typeof(a)) {
|
||||
case TInt:
|
||||
var a:Int = cast a;
|
||||
switch(Type.typeof(b)) {
|
||||
case TInt: a == cast(b, Int);
|
||||
case TFloat: a == cast(b, Float);
|
||||
default: false;
|
||||
}
|
||||
case TFloat:
|
||||
var a:Float = cast a;
|
||||
switch(Type.typeof(b)) {
|
||||
case TInt: a == cast(b, Int);
|
||||
case TFloat: a == cast(b, Float);
|
||||
default: false;
|
||||
}
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static function hasDecl(e:Expr):Bool {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EVar(_): true;// has a declaration
|
||||
case EFunction(_): true;// has a declaration
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static function getTypeName(e:Expr):String {
|
||||
if(e == null)
|
||||
return null;
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CInt(_)): "Int";
|
||||
case EConst(CFloat(_)): "Float";
|
||||
case EConst(CString(_)): "String";
|
||||
case EIdent("true") | EIdent("false"): "Bool";
|
||||
case EIdent("null"): "Null";
|
||||
case EIdent(_): "Dynamic";
|
||||
case EParent(e): getTypeName(e);
|
||||
default: Std.string(Tools.expr(e));
|
||||
}
|
||||
}
|
||||
|
||||
static function getConstType(e:Expr):ConstType {
|
||||
if(e == null)
|
||||
return null;
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CInt(_)): CTInt;
|
||||
case EConst(CFloat(_)): CTFloat;
|
||||
case EConst(CString(_)): CTString;
|
||||
case EIdent("true") | EIdent("false"): CTBool;
|
||||
case EIdent("null"): CTNull;
|
||||
case EParent(e): getConstType(e);
|
||||
default: throw "Unknown type " + Tools.expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
static function isConstant(e:Expr):Bool {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EIdent("true") | EIdent("false") | EIdent("null"): true;
|
||||
case EConst(_): true;
|
||||
case EParent(e): isConstant(e);
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static function isBool(e:Expr):Bool {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EIdent("true") | EIdent("false"): true;
|
||||
case EParent(e): isBool(e);
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static function isNumber(e:Expr):Bool {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CInt(_)): true;
|
||||
case EConst(CFloat(_)): true;
|
||||
case EParent(e): isNumber(e);
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static function getNumber(e:Expr):Dynamic {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CInt(value)): value;
|
||||
case EConst(CFloat(value)): value;
|
||||
case EParent(e): getNumber(e);
|
||||
default: throw "Unknown type " + Tools.expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
static function getBool(e:Expr):Bool {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EIdent("true"): true;
|
||||
case EIdent("false"): false;
|
||||
case EParent(e): getBool(e);
|
||||
default: throw "Unknown type " + Tools.expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
static function getInt(e:Expr):Null<Int> {
|
||||
if(e == null)
|
||||
return null;
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CInt(value)): value;
|
||||
case EParent(e): getInt(e);
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
static function getFloat(e:Expr):Null<Float> {
|
||||
if(e == null)
|
||||
return null;
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CFloat(value)): value;
|
||||
case EParent(e): getFloat(e);
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
static function isString(e:Expr):Bool {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CString(_)): true;
|
||||
case EParent(e): isString(e);
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static function getStringConstant(e:Expr):String {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EConst(CString(value)): value;
|
||||
case EParent(e): getStringConstant(e);
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
static function getConstant(e:Expr):Dynamic {
|
||||
return switch(Tools.expr(e)) {
|
||||
case EParent(e): getConstant(e);
|
||||
case EIdent("true"): true;
|
||||
case EIdent("false"): false;
|
||||
case EIdent("null"): null;
|
||||
case EConst(CInt(value)): value;
|
||||
case EConst(CFloat(value)): value;
|
||||
case EConst(CString(value)): value;
|
||||
default: throw "Unknown constant " + Tools.expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
static function convertConstant(value:Dynamic):ExprDef {
|
||||
return switch(Type.typeof(value)) {
|
||||
case TInt: EConst(CInt(value));
|
||||
case TFloat: EConst(CFloat(value));
|
||||
case TBool: EIdent(value == true ? "true" : "false");
|
||||
//case TString: EConst(CString(value));
|
||||
case TNull: EIdent("null");
|
||||
case TClass(String): EConst(CString(value));
|
||||
default: throw "Unknown type " + Type.typeof(value);
|
||||
}
|
||||
}
|
||||
|
||||
static function mk(e:ExprDef, s:Expr):Expr {
|
||||
#if hscriptPos
|
||||
return new Expr(e, s.pmin, s.pmax, s.origin, s.line);
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
static function optimizeOp(op:Binop, f1:Dynamic, f2:Dynamic):Dynamic {
|
||||
//trace("Optimizing " + f1 + " " + op + " " + f2);
|
||||
return switch(op) {
|
||||
case OpAdd: f1 + f2;
|
||||
case OpSub: f1 - f2;
|
||||
case OpMult: f1 * f2;
|
||||
case OpDiv: f1 / f2;
|
||||
case OpMod: f1 % f2;
|
||||
case OpAnd: f1 & f2;
|
||||
case OpOr: f1 | f2;
|
||||
case OpXor: f1 ^ f2;
|
||||
case OpShl: f1 << f2;
|
||||
case OpShr: f1 >> f2;
|
||||
case OpUShr: f1 >>> f2;
|
||||
case OpEq: f1 == f2;
|
||||
case OpNotEq: f1 != f2;
|
||||
case OpGte: f1 >= f2;
|
||||
case OpLte: f1 <= f2;
|
||||
case OpGt: f1 > f2;
|
||||
case OpLt: f1 < f2;
|
||||
case OpBoolOr: f1 == true || f2 == true;
|
||||
case OpBoolAnd: f1 == true && f2 == true;
|
||||
case OpNullCoal: f1 == null ? f2 : f1;
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ConstType {
|
||||
CTInt;
|
||||
CTFloat;
|
||||
CTBool;
|
||||
CTString;
|
||||
CTNull;
|
||||
}
|
||||
+815
-892
File diff suppressed because it is too large
Load Diff
@@ -1,107 +0,0 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.Expr;
|
||||
import hscript.Error;
|
||||
import hscript.Tools;
|
||||
import hscript.Parser;
|
||||
|
||||
@:access(hscript.Parser)
|
||||
class Postprocessor {
|
||||
static inline function expr(e:Expr) return Tools.expr(e);
|
||||
|
||||
static function mk(e:ExprDef, s:Expr):Expr {
|
||||
#if hscriptPos
|
||||
return new Expr(e, s.pmin, s.pmax, s.origin, s.line);
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
public static function processvars(e:Expr, ?vars:Array<String>) {
|
||||
if(vars == null) vars = [];
|
||||
for(v in getvars(e)) vars.push(v);
|
||||
e = _processvars(e, vars);
|
||||
|
||||
return mk(EInfo(new InfoClass(vars), e), e);
|
||||
}
|
||||
|
||||
private static function _processvars(e:Expr, vars:Array<String>):Expr {
|
||||
if(e == null) return null;
|
||||
var ge = e;
|
||||
var doExtra = true;
|
||||
var e = switch (expr(e)) {
|
||||
case EIdent(v) if (v is String):
|
||||
mk(EIdent(vars.indexOf(v)), e);
|
||||
case EVar(n, t, _e, p, s) if (n is String):
|
||||
mk(EVar(vars.indexOf(n), t, _e, p, s), e);
|
||||
case EImport(c, IAs(n)) if (n is String):
|
||||
mk(EVar(vars.indexOf(n), null, mk(EImport(c, IAsReturn), e), false, false), e);
|
||||
case EFunction(args, _e, n, r, p, s, o) if (n is String):
|
||||
var _args:Array<Argument> = [
|
||||
for (arg in args)
|
||||
new Argument(vars.indexOf(arg.name), arg.t, arg.opt, arg.value)
|
||||
];
|
||||
mk(EFunction(_args, _e, vars.indexOf(n), r, p, s, o), e);
|
||||
case EFunction(args, _e, null, r, p, s, o):
|
||||
var _args:Array<Argument> = [
|
||||
for (arg in args)
|
||||
new Argument(vars.indexOf(arg.name), arg.t, arg.opt, arg.value)
|
||||
];
|
||||
mk(EFunction(_args, _e, null, r, p, s, o), e);
|
||||
case ENew(cl, p) if (cl is String):
|
||||
var p = [for(arg in p) arg];
|
||||
mk(ENew(vars.indexOf(cl), p), e);
|
||||
case EClass(n, fls, extnd, i) if (n is String):
|
||||
var fls:Array<Expr> = [for(f in fls) f];
|
||||
mk(EClass(vars.indexOf(n), fls, extnd, i), e);
|
||||
case ETry(_e, v, t, ec) if (v is String):
|
||||
mk(ETry(_e, vars.indexOf(v), t, ec), e);
|
||||
case EFor(v, it, _e) if (v is String):
|
||||
mk(EFor(vars.indexOf(v), it, _e), e);
|
||||
case EForKeyValue(v, it, _e, ithv) if (v is String && ithv is String):
|
||||
mk(EForKeyValue(vars.indexOf(v), it, _e, vars.indexOf(ithv)), e);
|
||||
default: {
|
||||
doExtra = false;
|
||||
e;
|
||||
}
|
||||
};
|
||||
|
||||
e = Tools.map(e, function(e) {
|
||||
return _processvars(e, vars);
|
||||
});
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
public static function getvars(se:Expr, ?vars:Array<String>):Array<String> {
|
||||
inline function pushVar(v:VarN) {
|
||||
if(v is String) {
|
||||
var v:String = cast v;
|
||||
if (!vars.contains(v))
|
||||
vars.push(v);
|
||||
}
|
||||
};
|
||||
|
||||
if(vars == null) vars = [];
|
||||
Tools.iterExprRecursive(se, (e) -> {
|
||||
switch (expr(e)) {
|
||||
case EVar(n, t, e, _,_): pushVar(n);
|
||||
case EIdent(v): pushVar(v);
|
||||
case EFunction(args,e,name,_,_,_,_):
|
||||
pushVar(name);
|
||||
for (a in args) {
|
||||
pushVar(a.name);
|
||||
}
|
||||
case EFor(v,it,e): pushVar(v);
|
||||
case EForKeyValue(v,it,e,ithv): pushVar(ithv); pushVar(v);
|
||||
case ETry(e, v, _, ec): pushVar(v);
|
||||
case ENew(cl, params): pushVar(cl);
|
||||
case EClass(name, fls,_,_): pushVar(name);
|
||||
default:
|
||||
}
|
||||
});
|
||||
return vars;
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.Expr;
|
||||
import hscript.Error;
|
||||
import hscript.Tools;
|
||||
import hscript.Parser;
|
||||
|
||||
@:access(hscript.Parser)
|
||||
class Preprocessor {
|
||||
static inline function expr(e:Expr) return Tools.expr(e);
|
||||
|
||||
private static var importStackName:Array<String> = [];
|
||||
private static var importStackMode:Array<KImportMode> = [];
|
||||
private static function addImport(e:String, mode:KImportMode = INormal) {
|
||||
for(i in importStackName) if(i == e) return;
|
||||
importStackName.push(e);
|
||||
importStackMode.push(mode);
|
||||
}
|
||||
|
||||
private static function popImport(e:Expr) {
|
||||
return mk(EImport(importStackName.pop(), importStackMode.pop()), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocesses the expression, like 'a'.code => 97
|
||||
* Also for transforming any abstracts into their implementations (TODO)
|
||||
* Also for transforming any static extensions into their real form (TODO)
|
||||
* Also to automatically add imports for stuff that is not imported
|
||||
**/
|
||||
public static function process(e:Expr, top:Bool = true):Expr {
|
||||
importStackName = [];
|
||||
importStackMode = [];
|
||||
var e = _process(e, top);
|
||||
|
||||
// Automatically add imports for stuff
|
||||
switch(expr(e)) {
|
||||
case EBlock(exprs):
|
||||
while(importStackName.length > 0) {
|
||||
exprs.unshift(popImport(e));
|
||||
}
|
||||
return mk(EBlock(exprs), e);
|
||||
default:
|
||||
if(importStackName.length > 0) {
|
||||
var exprs = [];
|
||||
while(importStackName.length > 0) {
|
||||
exprs.unshift(popImport(e));
|
||||
}
|
||||
exprs.push(e);
|
||||
return mk(EBlock(exprs), e);
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private static function _process(e:Expr, top:Bool = true):Expr {
|
||||
if(e == null)
|
||||
return null;
|
||||
|
||||
// If stuff looks wrong, add this back
|
||||
//e = Tools.map(e, function(e) {
|
||||
// return _process(e, false);
|
||||
//});
|
||||
|
||||
//trace(expr(e));
|
||||
|
||||
switch(expr(e)) {
|
||||
case EField(expr(_) => EConst(CString(s)), "code", _): // Transform string.code into charCode
|
||||
if(s.length != 1) {
|
||||
throw Parser.getBaseError(EPreset(INVALID_CHAR_CODE_MULTI));
|
||||
}
|
||||
return mk(EConst(CInt(s.charCodeAt(0))), e);
|
||||
case ECall(expr(_) => EField(expr(_) => EIdent("String"), "fromCharCode", _), [e]): // Seperate this later?
|
||||
switch(expr(e)) { // should this be Optimizer?
|
||||
case EConst(CInt(i)):
|
||||
return mk(EConst(CString(String.fromCharCode(i))), e);
|
||||
default:
|
||||
}
|
||||
if(!Preprocessor.isStringFromCharCodeFixed) {
|
||||
// __StringWorkaround__fromCharCode(i);
|
||||
#if !NO_FROM_CHAR_CODE_FIX
|
||||
return mk(ECall(mk(EIdent("__StringWorkaround__fromCharCode"), e), [e]), e);
|
||||
#else
|
||||
throw Parser.getBaseError(EPreset(FROM_CHAR_CODE_NON_INT));
|
||||
#end
|
||||
}
|
||||
|
||||
// Automatically add imports for stuff
|
||||
case ENew("String", _): addImport("String");
|
||||
case EIdent("String"): addImport("String");
|
||||
case ENew("StringBuf", _): addImport("StringBuf");
|
||||
case EIdent("StringBuf"): addImport("StringBuf");
|
||||
case EIdent("Bool"): addImport("Bool");
|
||||
case EIdent("Float"): addImport("Float");
|
||||
case EIdent("Int"): addImport("Int");
|
||||
case ENew("IntIterator", _): addImport("IntIterator");
|
||||
case EIdent("IntIterator"): addImport("IntIterator");
|
||||
case EIdent("Array"): addImport("Array");
|
||||
|
||||
case EIdent("Sys"): addImport("Sys");
|
||||
case EIdent("Std"): addImport("Std");
|
||||
case EIdent("Type"): addImport("Type");
|
||||
case EIdent("Reflect"): addImport("Reflect");
|
||||
case EIdent("StringTools"): addImport("StringTools");
|
||||
case EIdent("Math"): addImport("Math");
|
||||
case ENew("Date", _): addImport("Date");
|
||||
case EIdent("Date"): addImport("Date");
|
||||
case EIdent("DateTools"): addImport("DateTools");
|
||||
case EIdent("Lambda"): addImport("Lambda");
|
||||
case ENew("Xml", _): addImport("Xml");
|
||||
case EIdent("Xml"): addImport("Xml");
|
||||
//case EIdent("List"): addImport("haxe.ds.List");
|
||||
|
||||
case ENew("EReg", _): addImport("EReg");
|
||||
case EIdent("EReg"): addImport("EReg");
|
||||
//case EField(expr(_) => EIdent("EReg"), "escape", _):
|
||||
// addImport("EReg");
|
||||
default:
|
||||
}
|
||||
|
||||
e = Tools.map(e, function(e) {
|
||||
return _process(e, false);
|
||||
});
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static function mk(e:ExprDef, s:Expr):Expr {
|
||||
#if hscriptPos
|
||||
return new Expr(e, s.pmin, s.pmax, s.origin, s.line);
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
public static var isStringFromCharCodeFixed(get, null):Null<Bool> = null;
|
||||
static function get_isStringFromCharCodeFixed():Null<Bool> {
|
||||
if(isStringFromCharCodeFixed == null) {
|
||||
try {
|
||||
Reflect.callMethod(null, Reflect.field(String, "fromCharCode"), [65]);
|
||||
isStringFromCharCodeFixed = true;
|
||||
} catch(e:Dynamic) {
|
||||
isStringFromCharCodeFixed = false;
|
||||
}
|
||||
}
|
||||
return isStringFromCharCodeFixed;
|
||||
}
|
||||
}
|
||||
+315
-477
@@ -30,33 +30,23 @@ class Printer {
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function exprToString( e : Expr ) {
|
||||
public function exprToString( e : Expr ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
expr(e);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static function convertExprToString( e : Expr ) {
|
||||
var printer = new Printer();
|
||||
return printer.exprToString(e);
|
||||
}
|
||||
|
||||
public function typeToString( t : CType ) {
|
||||
public function typeToString( t : CType ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
type(t);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static function convertTypeToString( t : CType ) {
|
||||
var printer = new Printer();
|
||||
return printer.typeToString(t);
|
||||
}
|
||||
inline function add<T>(s:T):Void buf.add(s);
|
||||
|
||||
inline function add<T>(s:T) buf.add(s);
|
||||
|
||||
function type( t : CType ) {
|
||||
function type( t : CType ):Void {
|
||||
switch( t ) {
|
||||
case CTOpt(t):
|
||||
add('?');
|
||||
@@ -78,14 +68,11 @@ class Printer {
|
||||
type(t);
|
||||
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||
add('(');
|
||||
var first = true;
|
||||
for (i=>a in args) {
|
||||
for (a in args)
|
||||
switch a {
|
||||
case CTNamed(_, _): type(a);
|
||||
default: type(CTNamed('_', a));
|
||||
}
|
||||
if( i != args.length - 1 ) add(", ");
|
||||
}
|
||||
add(')->');
|
||||
type(ret);
|
||||
case CTFun(args, ret):
|
||||
@@ -111,515 +98,366 @@ class Printer {
|
||||
add("(");
|
||||
type(t);
|
||||
add(")");
|
||||
case CTExpr(e):
|
||||
expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
function addType( t : CType ) {
|
||||
function addType( t : CType ):Void {
|
||||
if( t != null ) {
|
||||
add(" : ");
|
||||
type(t);
|
||||
}
|
||||
}
|
||||
|
||||
function block(e : Expr, addSpaceIfBlock : Bool = true) {
|
||||
var isBlock = Tools.expr(e).match(EBlock(_));
|
||||
if(isBlock) {
|
||||
if(addSpaceIfBlock) add(" ");
|
||||
} else {
|
||||
add("\n");
|
||||
tabs += "\t";
|
||||
add(tabs);
|
||||
}
|
||||
expr(e);
|
||||
|
||||
if(!isBlock) {
|
||||
//add("\n");
|
||||
tabs = tabs.substr(1);
|
||||
//add(tabs);
|
||||
}
|
||||
|
||||
return isBlock;
|
||||
}
|
||||
|
||||
function isJson(s:String) {
|
||||
var len = s.length;
|
||||
var i = 0;
|
||||
while (i < len) {
|
||||
switch (StringTools.fastCodeAt(s, i++)) {
|
||||
// [a-zA-Z0-9_]+
|
||||
case "a".code | "b".code | "c".code | "d".code | "e".code | "f".code | "g".code | "h".code | "i".code | "j".code | "k".code | "l".code | "m".code
|
||||
| "n".code | "o".code | "p".code | "q".code | "r".code | "s".code | "t".code | "u".code | "v".code | "w".code | "x".code | "y".code | "z".code
|
||||
| "A".code | "B".code | "C".code | "D".code | "E".code | "F".code | "G".code | "H".code | "I".code | "J".code | "K".code | "L".code | "M".code
|
||||
| "N".code | "O".code | "P".code | "Q".code | "R".code | "S".code | "T".code | "U".code | "V".code | "W".code | "X".code | "Y".code | "Z".code
|
||||
| "0".code | "1".code | "2".code | "3".code | "4".code | "5".code | "6".code | "7".code | "8".code | "9".code | "_".code:
|
||||
case _:
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline function isPrintable( c : Int ) {
|
||||
return c >= 32 && c <= 126;
|
||||
}
|
||||
|
||||
static inline function hex( c : Int, ?len : Int = 2 ) {
|
||||
return StringTools.hex(c, len).toLowerCase();
|
||||
}
|
||||
|
||||
public static function getEscapedString( s : String ) {
|
||||
var buf = new StringBuf();
|
||||
#if target.unicode
|
||||
var s = new UnicodeString(s);
|
||||
#end
|
||||
for( i in 0...s.length ) {
|
||||
#if target.unicode
|
||||
var c:Null<Int> = s.charCodeAt(i);
|
||||
#else
|
||||
var c:Null<Int> = StringTools.unsafeCodeAt(s, i);
|
||||
#end
|
||||
switch( c ) {
|
||||
case '"'.code: buf.add('\\"');
|
||||
case '\\'.code: buf.add('\\\\');
|
||||
case '\n'.code: buf.add('\\n');
|
||||
case '\r'.code: buf.add('\\r');
|
||||
case '\t'.code: buf.add('\\t');
|
||||
default:
|
||||
if(c == null) continue;
|
||||
if(isPrintable(c))
|
||||
buf.addChar(c);
|
||||
else {
|
||||
if(c > 0xFF) {
|
||||
buf.add("\\u{");
|
||||
buf.add(hex(c, null));
|
||||
buf.add("}");
|
||||
} else {
|
||||
buf.add("\\x");
|
||||
buf.add(hex((c & 0xFF)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
function getVar(v:VarN) {
|
||||
if( v == null ) {
|
||||
return ("??NULL??");
|
||||
}
|
||||
|
||||
if(v is Int) {
|
||||
return ("$" + v);
|
||||
} else {
|
||||
return (v);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getBinaryOp(op:Binop) {
|
||||
return switch(op) {
|
||||
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 OpNotEq: "!=";
|
||||
case OpGt: ">";
|
||||
case OpGte: ">=";
|
||||
case OpLt: "<";
|
||||
case OpLte: "<=";
|
||||
case OpBoolAnd: "&&";
|
||||
case OpBoolOr: "||";
|
||||
case OpIs: "is";
|
||||
case OpNullCoal: "??";
|
||||
case OpAssign: "=";
|
||||
case OpArrow: "=>";
|
||||
case OpInterval: "...";
|
||||
case OpAssignOp(op): getBinaryOp(op) + "=";
|
||||
}
|
||||
}
|
||||
|
||||
public static function getUnaryOp(op:Unop) {
|
||||
return switch(op) {
|
||||
case OpIncrement: "++";
|
||||
case OpDecrement: "--";
|
||||
case OpNot: "!";
|
||||
case OpNeg: "-";
|
||||
case OpNegBits: "~";
|
||||
case OpSpread: "...";
|
||||
}
|
||||
}
|
||||
|
||||
function expr( e : Expr ) {
|
||||
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);
|
||||
//}
|
||||
|
||||
// TODO: make else if print correctly
|
||||
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");
|
||||
|
||||
switch( Tools.expr(e) ) {
|
||||
case EImport(c, mode):
|
||||
add("import " + c);
|
||||
switch(mode) {
|
||||
case IAs(name): add(' as $name');
|
||||
case IAll: add('.*');
|
||||
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:
|
||||
}
|
||||
case EClass(name, fields, extend, interfaces):
|
||||
add('class ${getVar(name)}');
|
||||
if (extend != null)
|
||||
add(' extends $extend');
|
||||
for(_interface in interfaces) {
|
||||
add(' implements $_interface');
|
||||
switch(set) {
|
||||
case ADefault: add("default");
|
||||
case ANull: add("null");
|
||||
case ASet: add("set");
|
||||
case ADynamic: add("dynamic");
|
||||
case ANever: add("never");
|
||||
default:
|
||||
}
|
||||
add(' {\n');
|
||||
tabs += "\t";
|
||||
// TODO: Print fields
|
||||
//for(field in fields) {
|
||||
// expr(field);
|
||||
//}
|
||||
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 EConst(c):
|
||||
switch( c ) {
|
||||
case CInt(i): add(i);
|
||||
case CFloat(f): add(f);
|
||||
case CString(s):
|
||||
add('"');
|
||||
add(getEscapedString(s));
|
||||
add('"');
|
||||
}
|
||||
case EIdent(v):
|
||||
add(getVar(v));
|
||||
case EVar(n, t, e): // TODO: static, public, override
|
||||
add("var " + getVar(n));
|
||||
if( t != null )
|
||||
addType(t);
|
||||
else
|
||||
switch( Tools.expr(e) ) {
|
||||
case EMapDecl(type, _, _):
|
||||
add(" : Map<");
|
||||
switch( type ) {
|
||||
case ObjectMap: add("Dynamic");
|
||||
case StringMap: add("String");
|
||||
case EnumMap: add("EnumValue");
|
||||
case IntMap: add("Int");
|
||||
case UnknownMap: add("?");
|
||||
case Null: add("Null");
|
||||
}
|
||||
add(", Dynamic>");
|
||||
default:
|
||||
}
|
||||
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(tabs);
|
||||
add("}");
|
||||
}
|
||||
case EField(e, f, s):
|
||||
}
|
||||
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);
|
||||
add((s == true ? "?." : ".") + f);
|
||||
case EBinop(op, e1, e2):
|
||||
/*var op1 = switch(Tools.expr(e1)) {
|
||||
case EBinop(op, _, _): op;
|
||||
case EConst(_): "_";
|
||||
case EIdent(_): "_";
|
||||
default: null;
|
||||
} 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);
|
||||
}
|
||||
var op2 = switch(Tools.expr(e2)) {
|
||||
case EBinop(op, _, _): op;
|
||||
case EConst(_): "_";
|
||||
case EIdent(_): "_";
|
||||
default: null;
|
||||
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");
|
||||
}
|
||||
var paran = Tools.checkOpPrecedence(op, op1, op2);*/
|
||||
var paran = 2;
|
||||
|
||||
var op = getBinaryOp(op);
|
||||
|
||||
if(paran == 0 || paran == 2) {
|
||||
add("(");
|
||||
expr(e1);
|
||||
add(")");
|
||||
} else {
|
||||
expr(e1);
|
||||
}
|
||||
if(op == "...")
|
||||
add(op);
|
||||
else
|
||||
add(" " + op + " ");
|
||||
if(paran == 1 || paran == 2) {
|
||||
add("(");
|
||||
expr(e2);
|
||||
add(")");
|
||||
} else {
|
||||
expr(e2);
|
||||
}
|
||||
case EUnop(op, pre, e):
|
||||
var op = getUnaryOp(op);
|
||||
|
||||
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(")");
|
||||
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(a);
|
||||
}
|
||||
add(")");
|
||||
case EIf(cond,e1,e2):
|
||||
add("if( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
var wasBlock = block(e1, true);
|
||||
|
||||
if( e2 != null ) {
|
||||
if(!wasBlock) add("\n" + tabs);
|
||||
add(" else ");
|
||||
block(e2);
|
||||
}
|
||||
case EWhile(cond,e):
|
||||
add("while( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
block(e, true);
|
||||
case EDoWhile(cond,e):
|
||||
add("do");
|
||||
block(e, true);
|
||||
add(" while ( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
case EFor(v, it, e):
|
||||
add("for( "+getVar(v)+" in ");
|
||||
expr(it);
|
||||
add(" )");
|
||||
block(e, true);
|
||||
case EForKeyValue(v, it, e, ithv):
|
||||
add("for( "+getVar(ithv)+" => "+getVar(v)+" in ");
|
||||
expr(it);
|
||||
add(" )");
|
||||
block(e, true);
|
||||
case EBreak:
|
||||
add("break");
|
||||
case EContinue:
|
||||
add("continue");
|
||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||
add("function");
|
||||
if( name != null )
|
||||
add(" " + getVar(name));
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(getVar(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 EMapDecl(type, keys, values):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( i in 0...keys.length ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(keys[i]);
|
||||
add(" => ");
|
||||
expr(values[i]);
|
||||
}
|
||||
add("]");
|
||||
case EArrayDecl(el):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add("]");
|
||||
case ENew(cl, args):
|
||||
add("new " + getVar(cl) + "(");
|
||||
var first = true;
|
||||
for( e in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
case EThrow(e):
|
||||
add("throw ");
|
||||
expr(e);
|
||||
case ETry(e, v, t, ecatch):
|
||||
add("try");
|
||||
var wasBlock = block(e);
|
||||
if( !wasBlock ) {
|
||||
add("\n" + tabs);
|
||||
} else add(" ");
|
||||
add("catch( " + v);
|
||||
addType(t);
|
||||
add(" )");
|
||||
block(ecatch);
|
||||
case EObject(fl):
|
||||
if( fl.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( i=>f in fl ) {
|
||||
add(tabs);
|
||||
var name = isJson(f.name) ? "\"" + f.name + "\"" : f.name;
|
||||
add(name+" : ");
|
||||
expr(f.e);
|
||||
if( i != fl.length - 1 ) add(",");
|
||||
add("\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add(tabs);
|
||||
add("}");
|
||||
}
|
||||
case ETernary(c,e1,e2):
|
||||
expr(c);
|
||||
add(" ? ");
|
||||
expr(e1);
|
||||
add(" : ");
|
||||
expr(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
add("switch( ");
|
||||
expr(e);
|
||||
add(" ) {\n");
|
||||
tabs += "\t";
|
||||
for( c in cases ) {
|
||||
add(tabs);
|
||||
add("case ");
|
||||
var first = true;
|
||||
for( v in c.values ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(v);
|
||||
}
|
||||
add(":");
|
||||
block(c.expr, true);
|
||||
add(";\n");
|
||||
}
|
||||
if( def != null ) {
|
||||
add(tabs);
|
||||
add("default: ");
|
||||
block(def, true);
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add(tabs);
|
||||
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(")");
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
case EInfo(_, e):
|
||||
expr(e);
|
||||
#end
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
case ECheckType(e, t):
|
||||
add("(");
|
||||
expr(e);
|
||||
add(" : ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
public inline static function toString( e : Expr ) {
|
||||
public static function toString( e : Expr ):String {
|
||||
return new Printer().exprToString(e);
|
||||
}
|
||||
|
||||
public inline static function compareErrors( e1 : Error, e2 : Error ) {
|
||||
return Type.enumEq(Tools.cleanError(e1), Tools.cleanError(e2));
|
||||
}
|
||||
|
||||
public inline static function getPrintableError( e : Error ) {
|
||||
return Tools.cleanError(switch( Tools.cleanError(e) ) {
|
||||
case EPreset(msg): Parser.getBaseError(ECustom(msg.toString()));
|
||||
default: e;
|
||||
});
|
||||
}
|
||||
|
||||
public static function errorToString( e : Error ) {
|
||||
var message = switch( Tools.cleanError(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 EUnterminatedRegex: "Unterminated regular expression";
|
||||
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||
case EInvalidType(t): "Invalid type: "+t;
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f, on) if (on != null): "Invalid access to field " + f + " on " + on;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
case EPreset(msg): msg.toString();
|
||||
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||
case EInvalidEscape(s): "Invalid escape sequence: " + s;
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.utils.UnsafeReflect;
|
||||
import hscript.Interp;
|
||||
import hscript.Expr.FieldPropertyAccess;
|
||||
|
||||
/**
|
||||
* Special variable that handles 'getter/setter' function calls
|
||||
* depending of the read/write access combination.
|
||||
*
|
||||
* Example:
|
||||
* ```haxe
|
||||
* public var myvar(get, set):Int;
|
||||
* var _myvar:Int = 10;
|
||||
*
|
||||
* function get_myvar():Int {
|
||||
* return _myvar;
|
||||
* }
|
||||
*
|
||||
* function set_myvar(val:Int):Int {
|
||||
* if(val > 10) return _myvar = val;
|
||||
* return val;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see https://haxe.org/manual/class-field-property.html
|
||||
*/
|
||||
@:access(hscript.Interp)
|
||||
@:structInit
|
||||
class Property {
|
||||
private static inline var GET = 'get_';
|
||||
private static inline var SET = 'set_';
|
||||
|
||||
public var r:Dynamic;
|
||||
public var getter:FieldPropertyAccess;
|
||||
public var setter:FieldPropertyAccess;
|
||||
|
||||
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, isStatic:Bool, interp:Interp) {
|
||||
this.r = r;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.isVar = isVar;
|
||||
this.__isStatic = isStatic;
|
||||
this.interp = interp;
|
||||
}
|
||||
|
||||
var __allowReadAccess:Bool = false;
|
||||
var __allowWriteAccess:Bool = false;
|
||||
var __allowSetGet:Null<Bool> = null;
|
||||
final __isStatic:Bool = false;
|
||||
|
||||
public function callGetter(name:String) {
|
||||
switch (getter) {
|
||||
case AGet | ADynamic:
|
||||
var fName:String = '$GET$name';
|
||||
if (!__allowReadAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) {
|
||||
if (varExists(fName)) {
|
||||
return callAccessor(fName);
|
||||
} else
|
||||
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||
} else {
|
||||
if ((setter == ADefault || setter == ANull) || isVar)
|
||||
return r;
|
||||
else
|
||||
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||
}
|
||||
case ANever:
|
||||
interp.error(ECustom('This expression cannot be accessed for reading'));
|
||||
default:
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public function callSetter(name:String, val:Dynamic) {
|
||||
switch (setter) {
|
||||
case ASet | ADynamic:
|
||||
var fName:String = '$SET$name';
|
||||
if (!__allowWriteAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) {
|
||||
if (varExists(fName))
|
||||
return callAccessor(fName, [val], true);
|
||||
else
|
||||
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||
} else {
|
||||
if ((getter == ADefault || getter == ANull) || isVar)
|
||||
return r = val;
|
||||
else
|
||||
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||
}
|
||||
case ANever:
|
||||
interp.error(ECustom('This expression cannot be accessed for writing'));
|
||||
default:
|
||||
}
|
||||
|
||||
return r = val;
|
||||
}
|
||||
|
||||
private function callAccessor(f:String, ?args:Array<Dynamic>, isWrite:Bool = false):Dynamic {
|
||||
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
|
||||
var rt:Dynamic = null;
|
||||
if (fn != null && Reflect.isFunction(fn)) {
|
||||
if (isWrite) __allowWriteAccess = true;
|
||||
else __allowReadAccess = true;
|
||||
|
||||
rt = UnsafeReflect.callMethodUnsafe(null, fn, args == null ? [] : args);
|
||||
|
||||
if (isWrite) __allowWriteAccess = false;
|
||||
else __allowReadAccess = false;
|
||||
|
||||
return rt;
|
||||
} else
|
||||
interp.error(ECustom('Method $f required by property ${f.substr(3)} is missing'));
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
private function varExists(n:String) {
|
||||
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n);
|
||||
}
|
||||
}
|
||||
+82
-267
@@ -21,131 +21,77 @@
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
import hscript.utils.UnsafeReflect;
|
||||
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
||||
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||
switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_): f(e);
|
||||
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 EForKeyValue(_, 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 EMapDecl(type, keys, values): for( e in keys ) f(e); for( e in values ) f(e);
|
||||
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);
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
case EInfo(info, e): f(e);
|
||||
#end
|
||||
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 iterExprRecursive( ve : Expr, f : Expr -> Void ) {
|
||||
var rec = (e:Expr) -> iterExprRecursive(e, f);
|
||||
f(ve);
|
||||
switch( expr(ve) ) {
|
||||
case EConst(_), EIdent(_): {}
|
||||
case EImport(c, _): {}
|
||||
case EClass(_, e, _, _): for( a in e ) rec(a);
|
||||
case EVar(_, _, e): if( e != null ) rec(e);
|
||||
case EParent(e, _): rec(e);
|
||||
case EBlock(el): for( e in el ) rec(e);
|
||||
case EField(e, _): rec(e);
|
||||
case EBinop(_, e1, e2): rec(e1); rec(e2);
|
||||
case EUnop(_, _, e): rec(e);
|
||||
case ECall(e, args): rec(e); for( a in args ) rec(a);
|
||||
case EIf(c, e1, e2): rec(c); rec(e1); if( e2 != null ) rec(e2);
|
||||
case EWhile(c, e): rec(c); rec(e);
|
||||
case EDoWhile(c, e): rec(c); rec(e);
|
||||
case EFor(_, it, e): rec(it); rec(e);
|
||||
case EForKeyValue(_, it, e, _): rec(it); rec(e);
|
||||
case EBreak,EContinue: {}
|
||||
case EFunction(_, e, _, _): rec(e);
|
||||
case EReturn(e): if( e != null ) rec(e);
|
||||
case EArray(e, i): rec(e); rec(i);
|
||||
case EMapDecl(type, keys, values): for( e in keys ) rec(e); for( e in values ) rec(e);
|
||||
case EArrayDecl(el): for( e in el ) rec(e);
|
||||
case ENew(_,el): for( e in el ) rec(e);
|
||||
case EThrow(e): rec(e);
|
||||
case ETry(e, _, _, c): rec(e); rec(c);
|
||||
case EObject(fl): for( fi in fl ) rec(fi.e);
|
||||
case ETernary(c, e1, e2): rec(c); rec(e1); rec(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
rec(e);
|
||||
for( c in cases ) {
|
||||
for( v in c.values ) rec(v);
|
||||
rec(c.expr);
|
||||
}
|
||||
if( def != null ) rec(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) rec(a); rec(e);
|
||||
case ECheckType(e,_): rec(e);
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
case EInfo(info, e): rec(e);
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ) {
|
||||
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, p, s): EVar(n, t, if( e != null ) f(e) else null, p, s);
|
||||
case EParent(e, no): EParent(f(e), no);
|
||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||
case EField(e, fi, s): EField(f(e),fi,s);
|
||||
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 EForKeyValue(v, it, e, ithv): EForKeyValue(v, f(it), f(e), ithv);
|
||||
case EFunction(args, e, name, t, p, s, o): EFunction(args, f(e), name, t, p, s, o);
|
||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||
case EArray(e, i): EArray(f(e),f(i));
|
||||
case EMapDecl(type, keys, values): EMapDecl(type, [for( e in keys ) f(e)], [for( e in values ) f(e)]);
|
||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||
case 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 ) new ObjectField(fi.name, 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, m): EImport(c, m);
|
||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||
#if !HSCRIPT_NO_INT_VARS
|
||||
case EInfo(info, e): EInfo(info, f(e));
|
||||
#end
|
||||
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);
|
||||
}
|
||||
@@ -158,165 +104,34 @@ class Tools {
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function cleanError( e : Error ) {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
||||
#if hscriptPos
|
||||
return new Expr(e, p.pmin, p.pmax, p.origin, p.line);
|
||||
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
public static function isValidBinOp(op:String):Bool {
|
||||
if(op == ("??"+"=")) return true;
|
||||
return switch(op) {
|
||||
case "+" | "-" | "*" | "/" | "%" | "&" | "|" | "^" | "<<" | ">>" | ">>>" | "==" | "!=" | ">=" | "<=" | ">" | "<" | "||" | "&&" | "is" | "=" | "??" | "..." | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" | ">>>=": true;
|
||||
case "=>": true;
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getOpEnum(op:String):Binop {
|
||||
return switch(op) {
|
||||
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 "!=": OpNotEq;
|
||||
case ">=": OpGte;
|
||||
case "<=": OpLte;
|
||||
case ">": OpGt;
|
||||
case "<": OpLt;
|
||||
case "||": OpBoolOr;
|
||||
case "&&": OpBoolAnd;
|
||||
case "is": OpIs;
|
||||
case "=": OpAssign;
|
||||
case "=>": OpArrow;
|
||||
case "??": OpNullCoal;
|
||||
case "...": OpInterval;
|
||||
default: {
|
||||
var op2 = op.substr(0, op.length - 1);
|
||||
if(isValidBinOp(op2)) {
|
||||
return OpAssignOp(getOpEnum(op2));
|
||||
}
|
||||
throw "Unknown binary operator: " + op;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getUnopEnum(op:String):Unop {
|
||||
return switch(op) {
|
||||
case "++": OpIncrement;
|
||||
case "--": OpDecrement;
|
||||
case "!": OpNot;
|
||||
case "-": OpNeg;
|
||||
case "~": OpNegBits;
|
||||
case "...": OpSpread;
|
||||
default: throw "Unknown unary operator: " + op;
|
||||
}
|
||||
}
|
||||
|
||||
static var priorities = [
|
||||
["%"],
|
||||
["*", "/"],
|
||||
["+", "-"],
|
||||
["<<", ">>", ">>>"],
|
||||
["|", "&", "^"],
|
||||
["==", "!=", ">", "<", ">=", "<="],
|
||||
["..."],
|
||||
["&&"],
|
||||
["||"],
|
||||
["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>","??"+"="],
|
||||
["->", "??"],
|
||||
["is"]
|
||||
];
|
||||
public static function checkOpPrecedence(mainOp:String, leftOp:String, rightOp:String):Int {
|
||||
var mainOpGroup = getOpGroup(mainOp);
|
||||
var leftOpGroup = getOpGroup(leftOp);
|
||||
var rightOpGroup = getOpGroup(rightOp);
|
||||
|
||||
var leftParam = false;
|
||||
var rightParam = false;
|
||||
|
||||
if(leftOpGroup > mainOpGroup && leftOpGroup != -1) leftParam = true;
|
||||
if(rightOpGroup > mainOpGroup && rightOpGroup != -1) rightParam = true;
|
||||
|
||||
if(!leftParam && !rightParam) {
|
||||
var mainOpIndex = getOpIndex(mainOp);
|
||||
var leftOpIndex = getOpIndex(leftOp);
|
||||
var rightOpIndex = getOpIndex(rightOp);
|
||||
|
||||
if(mainOpGroup == rightOpGroup) {
|
||||
if(rightOpIndex < mainOpIndex) rightParam = true;
|
||||
}
|
||||
if(leftOpGroup == mainOpGroup) {
|
||||
if(leftOpIndex < mainOpIndex) leftParam = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to index
|
||||
if(!leftParam && !rightParam) return -1;
|
||||
if(leftParam && rightParam) return 2;
|
||||
if(leftParam) return 0;
|
||||
if(rightParam) return 1;
|
||||
/**
|
||||
* 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 getOpIndex(op:String):Int {
|
||||
if(op == "_") return -1;
|
||||
var i = 0;
|
||||
for(p in priorities) {
|
||||
for(pp in p) {
|
||||
if(op == pp)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
||||
return obj != null && obj is IHScriptAbstractBehaviour;
|
||||
|
||||
public static function getOpGroup(op:String):Int {
|
||||
if(op == "_") return -1;
|
||||
var i = 0;
|
||||
for(p in priorities) {
|
||||
for(pp in p) {
|
||||
if(op == pp)
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
public static function getEnum(cl:Enum<Dynamic>):Dynamic {
|
||||
var enumThingy:Dynamic = {};
|
||||
for (c in cl.getConstructors()) {
|
||||
try {
|
||||
UnsafeReflect.setField(enumThingy, c, cl.createByName(c));
|
||||
} catch(e) {
|
||||
try {
|
||||
UnsafeReflect.setField(enumThingy, c, Reflect.makeVarArgs((args:Array<Dynamic>) -> cl.createByName(c, args)));
|
||||
} catch(ex) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return enumThingy;
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,12 @@ import haxe.macro.Compiler;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class UsingHandler {
|
||||
class AbstractHandler {
|
||||
public static function init() {
|
||||
#if !display
|
||||
if(Context.defined("display")) return;
|
||||
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.UsingHandler.build())');
|
||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -10,10 +10,10 @@ import haxe.macro.Type.FieldKind;
|
||||
import haxe.macro.Type.ClassField;
|
||||
import haxe.macro.Type.VarAccess;
|
||||
import haxe.macro.*;
|
||||
import Sys;
|
||||
|
||||
using StringTools;
|
||||
|
||||
// BIG TODO: make typed classes scriptable
|
||||
class ClassExtendMacro {
|
||||
public static inline final FUNC_PREFIX = "_HX_SUPER__";
|
||||
public static inline final CLASS_SUFFIX = "_HSX";
|
||||
@@ -29,6 +29,7 @@ class ClassExtendMacro {
|
||||
for(apply in Config.ALLOWED_CUSTOM_CLASSES) {
|
||||
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())");
|
||||
}
|
||||
//Context.onAfterTyping(buildTyped);
|
||||
#end
|
||||
#end
|
||||
}
|
||||
@@ -60,20 +61,20 @@ class ClassExtendMacro {
|
||||
if(key == "away3d.tools.commands.SphereMaker") return fields; // Error: Unknown identifier
|
||||
if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier
|
||||
if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined
|
||||
if(fkey == "hscript.CustomClassHandler.CustomTemplateClass") return fields; // Error: Redefined
|
||||
if(fkey == "hscript.CustomClass") return fields; // Error: Redefined
|
||||
if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined
|
||||
if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields;
|
||||
if(cl.module.contains("_")) return fields; // Weird issue, sorry
|
||||
|
||||
var superFields = [];
|
||||
if(cl.superClass != null) {
|
||||
if(false && cl.superClass != null) {
|
||||
var _superFields = cl.superClass.t.get().fields.get();
|
||||
_superFields = []; // Comment to enable super support, (broken)
|
||||
for(field in _superFields) {
|
||||
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||
continue;
|
||||
|
||||
function convertField(field:ClassField) {
|
||||
try {
|
||||
var nfield = @:privateAccess TypeTools.toField(field);
|
||||
var nfield = FixedTypeTools.toSimpleField(field);
|
||||
switch ([field.kind, field.type]) {
|
||||
case [FMethod(kind), TFun(args, ret)]:
|
||||
if(kind == MethInline)
|
||||
@@ -86,9 +87,9 @@ class ClassExtendMacro {
|
||||
switch(nfield.kind) {
|
||||
case FFun(fun):
|
||||
if (fun.params != null && fun.params.length > 0)
|
||||
continue;
|
||||
return null;
|
||||
|
||||
fun.ret = Utils.fixStdTypes(fun.ret);
|
||||
//sfun.ret = Utils.fixStdTypes(fun.ret);
|
||||
|
||||
var metas = nfield.meta;
|
||||
var defaultValues:Map<String, Dynamic> = [];
|
||||
@@ -107,7 +108,7 @@ class ClassExtendMacro {
|
||||
if(m.name == ":generic")
|
||||
isGeneric = true;
|
||||
}
|
||||
if(isGeneric) continue;
|
||||
if(isGeneric) return null;
|
||||
|
||||
if(defaultEntry != null)
|
||||
metas.remove(defaultEntry);
|
||||
@@ -119,20 +120,80 @@ class ClassExtendMacro {
|
||||
arg.opt = false;
|
||||
}
|
||||
|
||||
arg.type = Utils.fixStdTypes(arg.type);
|
||||
arg.type = null;//Utils.fixStdTypes(arg.type);
|
||||
|
||||
if(arg.opt) {
|
||||
if(arg.type.getParameters()[0].name != "Null")
|
||||
arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>};
|
||||
}
|
||||
//if(arg.opt) {
|
||||
// if(arg.type.getParameters()[0].name != "Null")
|
||||
// arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>};
|
||||
//}
|
||||
}
|
||||
|
||||
trace(nfield.name);
|
||||
default:
|
||||
}
|
||||
superFields.push(nfield);
|
||||
return nfield;
|
||||
} catch(e) {
|
||||
|
||||
trace(field.name, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var didPrint = false;
|
||||
|
||||
var fieldNames = [for(f in fields) f.name];
|
||||
|
||||
/*for(field in _superFields) {
|
||||
if(fieldNames.contains(field.name))
|
||||
continue;
|
||||
|
||||
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||
continue;
|
||||
|
||||
if(field.name.startsWith("get_")) {
|
||||
var access = FixedTypeTools.getAccess(field);
|
||||
if(access.contains(AInline) || access.contains(AFinal) || field.isFinal)
|
||||
continue;
|
||||
var name = field.name;
|
||||
superFields.push({
|
||||
name: field.name,
|
||||
pos: field.pos,
|
||||
kind: FFun({
|
||||
ret: null,
|
||||
params: [],
|
||||
expr: macro {
|
||||
return super.$name();
|
||||
},
|
||||
args: []
|
||||
}),
|
||||
access: access,
|
||||
meta: field.meta.get(),
|
||||
});
|
||||
//var f = convertField(field);
|
||||
//if(f != null)
|
||||
// superFields.push(f);
|
||||
if(field.name == "get_bgColor") {
|
||||
if(!didPrint) {
|
||||
trace(cl.name);
|
||||
didPrint = true;
|
||||
}
|
||||
trace("> " + field.name + " : " + access, field);
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
// want to get this working
|
||||
/*for(field in _superFields) {
|
||||
if(fieldNames.contains(field.name))
|
||||
continue;
|
||||
|
||||
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||
continue;
|
||||
|
||||
var f = convertField(field);
|
||||
if(f != null)
|
||||
superFields.push(f);
|
||||
}*/
|
||||
//superFields = [];
|
||||
}
|
||||
|
||||
@@ -152,11 +213,20 @@ class ClassExtendMacro {
|
||||
continue;
|
||||
if (f.name == "new") {
|
||||
hasNew = true;
|
||||
switch (f.kind) {
|
||||
case FFun(fn):
|
||||
var constructor:Field = buildConstructor(fn.args);
|
||||
|
||||
shadowClass.fields.push(constructor);
|
||||
definedFields.push(f.name);
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (f.name.startsWith(FUNC_PREFIX))
|
||||
continue;
|
||||
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline))
|
||||
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline) || f.access.contains(AFinal))
|
||||
continue;
|
||||
|
||||
if(f.name == "hget" || f.name == "hset") continue; // sorry, no overwriting the hget and hset in custom classes, yet
|
||||
@@ -187,27 +257,24 @@ class ClassExtendMacro {
|
||||
overrideExpr = macro {
|
||||
var name:String = $v{name};
|
||||
|
||||
if (__custom__variables != null) {
|
||||
if(__custom__variables.exists(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __custom__variables.get(name))) {
|
||||
return v($a{arguments});
|
||||
}
|
||||
if (__interp != null && __class__fields.contains(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||
return v($a{arguments});
|
||||
}
|
||||
}
|
||||
|
||||
return super.$name($a{arguments});
|
||||
};
|
||||
} else {
|
||||
overrideExpr = macro {
|
||||
var name:String = $v{name};
|
||||
|
||||
if (__custom__variables != null) {
|
||||
if(__custom__variables.exists(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __custom__variables.get(name))) {
|
||||
v($a{arguments});
|
||||
return;
|
||||
}
|
||||
if (__interp != null && __class__fields.contains(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||
v($a{arguments});
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.$name($a{arguments});
|
||||
@@ -272,7 +339,6 @@ class ClassExtendMacro {
|
||||
pack: cl.pack.copy(),
|
||||
name: cl.name
|
||||
}, [
|
||||
{name: "IHScriptCustomBehaviour", pack: ["hscript"]},
|
||||
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
|
||||
], false, true, false);
|
||||
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
||||
@@ -282,35 +348,45 @@ class ClassExtendMacro {
|
||||
|
||||
// Adding hscript getters and setters
|
||||
|
||||
// TODO: Remove
|
||||
shadowClass.fields.push({
|
||||
name: "__cachedFieldSet",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(macro: Map<String, Dynamic>),
|
||||
access: [APublic, AStatic]
|
||||
});
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "__interp",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(TPath({
|
||||
pack: ['hscript'],
|
||||
name: 'Interp'
|
||||
})),
|
||||
kind: FVar(macro: hscript.Interp),
|
||||
access: [APublic]
|
||||
});
|
||||
|
||||
/*
|
||||
shadowClass.fields.push({
|
||||
name: "__custom__variables",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(TPath({
|
||||
pack: [],
|
||||
name: 'Map',
|
||||
params: [TPType(TPath({name: "String", pack: []})), TPType(TPath({name: "Dynamic", pack: []}))]
|
||||
})),
|
||||
kind: FVar(macro: Map<String, Dynamic>),
|
||||
access: [APublic]
|
||||
});
|
||||
*/
|
||||
shadowClass.fields.push({
|
||||
name: "__allowSetGet",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(macro: Bool, macro true),
|
||||
access: [APublic]
|
||||
});
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "__allowSetGet",
|
||||
name: "__real_fields",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(TPath({
|
||||
pack: [],
|
||||
name: 'Bool',
|
||||
}), macro true),
|
||||
kind: FVar(macro: Array<String>),
|
||||
access: [APublic]
|
||||
});
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "__class__fields",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(macro: Array<String>),
|
||||
access: [APublic]
|
||||
});
|
||||
|
||||
@@ -318,20 +394,17 @@ class ClassExtendMacro {
|
||||
name: "__callGetter",
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
ret: TPath({name: 'Dynamic', pack: []}),
|
||||
ret: macro: Dynamic,
|
||||
params: [],
|
||||
expr: macro {
|
||||
__allowSetGet = false;
|
||||
var v = __custom__variables.get("get_" + name)();
|
||||
__allowSetGet = true;
|
||||
return v;
|
||||
return null;
|
||||
},
|
||||
args: [
|
||||
{
|
||||
name: "name",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "String", pack: []})
|
||||
type: macro: String
|
||||
}
|
||||
]
|
||||
}),
|
||||
@@ -342,26 +415,23 @@ class ClassExtendMacro {
|
||||
name: "__callSetter",
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
ret: TPath({name: 'Dynamic', pack: []}),
|
||||
ret: macro: Dynamic,
|
||||
params: [],
|
||||
expr: macro {
|
||||
__allowSetGet = false;
|
||||
var v = __custom__variables.get("set_" + name)(val);
|
||||
__allowSetGet = true;
|
||||
return v;
|
||||
return null;
|
||||
},
|
||||
args: [
|
||||
{
|
||||
name: "name",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "String", pack: []})
|
||||
type: macro: String
|
||||
},
|
||||
{
|
||||
name: "val",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "Dynamic", pack: []})
|
||||
type: macro: Dynamic
|
||||
}
|
||||
]
|
||||
}),
|
||||
@@ -410,42 +480,116 @@ class ClassExtendMacro {
|
||||
|
||||
var hgetField = if(hasHgetInSuper) {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||
return __callGetter(name);
|
||||
if (__custom__variables.exists(name))
|
||||
return __custom__variables.get(name);
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callGetter(name);
|
||||
return v;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.getField(name);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.hget(name);
|
||||
}
|
||||
} else {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||
return __callGetter(name);
|
||||
if (__custom__variables.exists(name))
|
||||
return __custom__variables.get(name);
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callGetter(name);
|
||||
return v;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.getField(name);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UnsafeReflect.getProperty(this, name);
|
||||
}
|
||||
}
|
||||
|
||||
var hsetField = if(hasHsetInSuper) {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||
return __callSetter(name, val);
|
||||
if (__custom__variables.exists(name)) {
|
||||
__custom__variables.set(name, val);
|
||||
return val;
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callSetter(name, val);
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.setField(name, val);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.hset(this, name);
|
||||
|
||||
if(__real_fields.contains(name)) {
|
||||
UnsafeReflect.setProperty(this, name, val);
|
||||
return UnsafeReflect.field(this, name);
|
||||
}
|
||||
return super.hset(name, val);
|
||||
}
|
||||
} else {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||
return __callSetter(name, val);
|
||||
if (__custom__variables.exists(name)) {
|
||||
__custom__variables.set(name, val);
|
||||
return val;
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callSetter(name, val);
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.setField(name, val);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
UnsafeReflect.setProperty(this, name, val);
|
||||
return UnsafeReflect.field(this, name);
|
||||
|
||||
if(__real_fields.contains(name)) {
|
||||
UnsafeReflect.setProperty(this, name, val);
|
||||
return UnsafeReflect.field(this, name);
|
||||
}
|
||||
//__custom__variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,7 +602,7 @@ class ClassExtendMacro {
|
||||
pos: Context.currentPos(),
|
||||
access: hasHsetInSuper ? [AOverride, APublic] : [APublic],
|
||||
kind: FFun({
|
||||
ret: TPath({name: 'Dynamic', pack: []}),
|
||||
ret: macro: Dynamic,
|
||||
params: [],
|
||||
expr: hsetField,
|
||||
args: [
|
||||
@@ -466,13 +610,13 @@ class ClassExtendMacro {
|
||||
name: "name",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "String", pack: []})
|
||||
type: macro: String
|
||||
},
|
||||
{
|
||||
name: "val",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "Dynamic", pack: []})
|
||||
type: macro: Dynamic
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -483,7 +627,7 @@ class ClassExtendMacro {
|
||||
pos: Context.currentPos(),
|
||||
access: hasHgetInSuper ? [AOverride, APublic] : [APublic],
|
||||
kind: FFun({
|
||||
ret: TPath({name: 'Dynamic', pack: []}),
|
||||
ret: macro: Dynamic,
|
||||
params: [],
|
||||
expr: hgetField,
|
||||
args: [
|
||||
@@ -491,7 +635,7 @@ class ClassExtendMacro {
|
||||
name: "name",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "String", pack: []})
|
||||
type: macro: String
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -509,6 +653,51 @@ class ClassExtendMacro {
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
static function buildConstructor(constArgs:Array<FunctionArg>):Field {
|
||||
var superCallArgs:Array<Expr> = [for (arg in constArgs) macro $i{arg.name}];
|
||||
|
||||
return {
|
||||
name: 'new',
|
||||
access: [APublic],
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
args: constArgs,
|
||||
expr: macro {
|
||||
// Call the super constructor with appropriate args
|
||||
super($a{superCallArgs});
|
||||
|
||||
if(__cachedFieldSet != null) {
|
||||
for(k => v in __cachedFieldSet) {
|
||||
Reflect.setProperty(this, k, v);
|
||||
}
|
||||
__cachedFieldSet.clear();
|
||||
__cachedFieldSet = null;
|
||||
}
|
||||
}
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
static function buildTyped(modules:Array<haxe.macro.Type.ModuleType>) {
|
||||
for(m in modules) {
|
||||
switch(m) {
|
||||
case TClassDecl(c):
|
||||
var cl = c.get();
|
||||
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface)
|
||||
continue;
|
||||
if (cl.params.length == 0)
|
||||
continue;
|
||||
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC"))
|
||||
buildTypedClass(cl);
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function buildTypedClass(cl:ClassType) {}
|
||||
|
||||
static function buildShadowClass(cl:ClassType) {}
|
||||
}
|
||||
#else
|
||||
class ClassExtendMacro {
|
||||
|
||||
@@ -0,0 +1,529 @@
|
||||
package hscript.macros;
|
||||
|
||||
/*
|
||||
* Copyright (C)2005-2019 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.
|
||||
*/
|
||||
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
import Type as StdType;
|
||||
|
||||
using Lambda;
|
||||
|
||||
/**
|
||||
This class provides some utility methods to work with types. It is
|
||||
best used through 'using haxe.macro.TypeTools' syntax and then provides
|
||||
additional methods on haxe.macro.Type instances.
|
||||
**/
|
||||
#if hl
|
||||
@:hlNative("macro")
|
||||
#end
|
||||
class FixedTypeTools {
|
||||
static function nullable(complexType:ComplexType):ComplexType
|
||||
return macro:Null<$complexType>;
|
||||
|
||||
public static function toField(cf:ClassField):Field {
|
||||
function varAccessToString(va:VarAccess, getOrSet:String):String {
|
||||
return {
|
||||
switch (va) {
|
||||
case AccNormal | AccCtor: "default";
|
||||
case AccNo: "null";
|
||||
case AccNever: "never";
|
||||
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
|
||||
case AccCall: getOrSet;
|
||||
case AccInline: "default";
|
||||
case AccRequire(_, _): "default";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var access = cf.isPublic ? [APublic] : [APrivate];
|
||||
if (cf.meta.has(":final")) {
|
||||
access.push(AFinal);
|
||||
}
|
||||
|
||||
if (cf.params.length != 0)
|
||||
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
|
||||
|
||||
return {
|
||||
name: cf.name,
|
||||
doc: cf.doc,
|
||||
access: access,
|
||||
kind: switch ([cf.kind, cf.type]) {
|
||||
case [FVar(read, write), ret]:
|
||||
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
|
||||
case [FMethod(_), TFun(args, ret)]:
|
||||
Sys.println("Converting " + cf.name);
|
||||
FFun({
|
||||
args: [
|
||||
for (a in args)
|
||||
{
|
||||
name: a.name,
|
||||
opt: a.opt,
|
||||
type: toComplexType(a.t),
|
||||
}
|
||||
],
|
||||
ret: toComplexType(ret),
|
||||
expr: null,
|
||||
});
|
||||
case [FMethod(_), TLazy(f)]:
|
||||
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
|
||||
switch(f()) {
|
||||
case TFun(args, ret):
|
||||
FFun({
|
||||
args: [
|
||||
for (a in args)
|
||||
{
|
||||
name: a.name,
|
||||
opt: a.opt,
|
||||
type: toComplexType(a.t),
|
||||
}
|
||||
],
|
||||
ret: toComplexType(ret),
|
||||
expr: null,
|
||||
});
|
||||
default:
|
||||
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||
}
|
||||
default:
|
||||
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||
},
|
||||
pos: cf.pos,
|
||||
meta: cf.meta.get(),
|
||||
}
|
||||
}
|
||||
|
||||
public static function getAccess(cf:ClassField):Array<Access> {
|
||||
var access = cf.isPublic ? [APublic] : [APrivate];
|
||||
if (cf.meta.has(":final") || cf.isFinal) {
|
||||
access.push(AFinal);
|
||||
}
|
||||
switch ([cf.kind, cf.type]) {
|
||||
case [FMethod(kind), TFun(_, _)] | [FMethod(kind), TLazy(_)]:
|
||||
if(kind == MethInline)
|
||||
access.push(AInline);
|
||||
if(kind == MethDynamic)
|
||||
access.push(ADynamic);
|
||||
default:
|
||||
}
|
||||
return access;
|
||||
}
|
||||
|
||||
public static function toSimpleField(cf:ClassField):Field {
|
||||
function varAccessToString(va:VarAccess, getOrSet:String):String {
|
||||
return {
|
||||
switch (va) {
|
||||
case AccNormal | AccCtor: "default";
|
||||
case AccNo: "null";
|
||||
case AccNever: "never";
|
||||
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
|
||||
case AccCall: getOrSet;
|
||||
case AccInline: "default";
|
||||
case AccRequire(_, _): "default";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var access = cf.isPublic ? [APublic] : [APrivate];
|
||||
if (cf.meta.has(":final")) {
|
||||
access.push(AFinal);
|
||||
}
|
||||
|
||||
if (cf.params.length != 0)
|
||||
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
|
||||
|
||||
return {
|
||||
name: cf.name,
|
||||
doc: cf.doc,
|
||||
access: access,
|
||||
kind: switch ([cf.kind, cf.type]) {
|
||||
case [FVar(read, write), ret]:
|
||||
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
|
||||
case [FMethod(_), TFun(args, ret)]:
|
||||
Sys.println("Converting " + cf.name);
|
||||
FFun({
|
||||
args: [
|
||||
for (a in args)
|
||||
{
|
||||
name: a.name,
|
||||
opt: a.opt,
|
||||
type: null,//toComplexType(a.t),
|
||||
}
|
||||
],
|
||||
ret: null,//toComplexType(ret),
|
||||
expr: null,
|
||||
});
|
||||
case [FMethod(_), TLazy(f)]:
|
||||
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
|
||||
switch(f()) {
|
||||
case TFun(args, ret):
|
||||
FFun({
|
||||
args: [
|
||||
for (a in args)
|
||||
{
|
||||
name: a.name,
|
||||
opt: a.opt,
|
||||
type: null,//toComplexType(a.t),
|
||||
}
|
||||
],
|
||||
ret: null,//toComplexType(ret),
|
||||
expr: null,
|
||||
});
|
||||
default:
|
||||
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||
}
|
||||
default:
|
||||
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||
},
|
||||
pos: cf.pos,
|
||||
meta: cf.meta.get(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a syntax-level type corresponding to Type `t`.
|
||||
|
||||
This function is mostly inverse to `ComplexTypeTools.toType`, but may
|
||||
lose some information on types that do not have a corresponding syntax
|
||||
version, such as monomorphs. In these cases, the result is null.
|
||||
|
||||
If `t` is null, an internal exception is thrown.
|
||||
**/
|
||||
public static function toComplexType(type:Null<Type>):Null<ComplexType>
|
||||
return {
|
||||
#if macro
|
||||
Context.toComplexType(type);
|
||||
#else
|
||||
switch (type) {
|
||||
case null:
|
||||
null;
|
||||
case TMono(_.get() => t):
|
||||
t == null ? null : toComplexType(t);
|
||||
case TEnum(_.get() => baseType, params):
|
||||
TPath(toTypePath(baseType, params));
|
||||
case TInst(_.get() => classType, params):
|
||||
switch (classType.kind) {
|
||||
case KTypeParameter(_):
|
||||
TPath({
|
||||
name: classType.name,
|
||||
pack: [],
|
||||
});
|
||||
default:
|
||||
TPath(toTypePath(classType, params));
|
||||
}
|
||||
case TType(_.get() => baseType, params):
|
||||
TPath(toTypePath(baseType, params));
|
||||
case TFun(args, ret):
|
||||
TFunction([for (a in args) a.opt ? nullable(toComplexType(a.t)) : toComplexType(a.t)], toComplexType(ret));
|
||||
case TAnonymous(_.get() => {fields: fields}):
|
||||
TAnonymous([for (cf in fields) toField(cf)]);
|
||||
case TDynamic(t):
|
||||
if (t == null) {
|
||||
macro:Dynamic;
|
||||
} else {
|
||||
var ct = toComplexType(t);
|
||||
macro:Dynamic<$ct>;
|
||||
}
|
||||
case TLazy(f):
|
||||
toComplexType(f());
|
||||
case TAbstract(_.get() => baseType, params):
|
||||
TPath(toTypePath(baseType, params));
|
||||
default:
|
||||
throw "Invalid type";
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
static function toTypeParam(type:Type):TypeParam
|
||||
return {
|
||||
switch (type) {
|
||||
case TInst(_.get() => {kind: KExpr(e)}, _): TPExpr(e);
|
||||
case _: TPType(toComplexType(type));
|
||||
}
|
||||
}
|
||||
|
||||
static function toTypePath(baseType:BaseType, params:Array<Type>):TypePath
|
||||
return {
|
||||
var module = baseType.module;
|
||||
{
|
||||
pack: baseType.pack,
|
||||
name: module.substring(module.lastIndexOf(".") + 1),
|
||||
sub: baseType.name,
|
||||
params: [for (t in params) toTypeParam(t)],
|
||||
}
|
||||
}
|
||||
|
||||
#if macro
|
||||
/**
|
||||
Follows all typedefs of `t` to reach the actual type.
|
||||
|
||||
If `once` is true, this function does not call itself recursively,
|
||||
otherwise it does. This can be useful in cases where intermediate
|
||||
typedefs might be of interest.
|
||||
|
||||
Affected types are monomorphs `TMono` and typedefs `TType(t,pl)`.
|
||||
|
||||
If `t` is null, an internal exception is thrown.
|
||||
|
||||
Usage example with monomorphs:
|
||||
var t = Context.typeof(macro null); // TMono(<mono>)
|
||||
var ts = Context.typeof(macro "foo"); //TInst(String,[])
|
||||
Context.unify(t, ts);
|
||||
trace(t); // TMono(<mono>)
|
||||
trace(t.follow()); //TInst(String,[])
|
||||
|
||||
Usage example with typedefs:
|
||||
var t = Context.typeof(macro ("foo" :MyString)); // typedef MyString = String
|
||||
trace(t); // TType(MyString,[])
|
||||
trace(t.follow()); //TInst(String,[])
|
||||
**/
|
||||
static public inline function follow(t:Type, ?once:Bool):Type
|
||||
return Context.follow(t, once);
|
||||
|
||||
/**
|
||||
Like `follow`, follows all typedefs of `t` to reach the actual type.
|
||||
|
||||
Will however follow also abstracts to their underlying implementation,
|
||||
if they are not a @:coreType abstract
|
||||
|
||||
If `t` is null, an internal exception is thrown.
|
||||
|
||||
Usage example:
|
||||
var t = Context.typeof(macro new Map<String, String>());
|
||||
trace(t); // TAbstract(Map,[TInst(String,[]),TInst(String,[])])
|
||||
trace(t.followWithAbstracts()); // TInst(haxe.ds.StringMap, [TInst(String,[])])
|
||||
**/
|
||||
static public inline function followWithAbstracts(t:Type, once:Bool = false):Type
|
||||
return Context.followWithAbstracts(t, once);
|
||||
|
||||
/**
|
||||
Returns true if `t1` and `t2` unify, false otherwise.
|
||||
**/
|
||||
static public inline function unify(t1:Type, t2:Type):Bool
|
||||
return Context.unify(t1, t2);
|
||||
|
||||
/**
|
||||
Tries to extract the class instance stored inside `t`.
|
||||
|
||||
If `t` is a class instance `TInst(c,pl)`, c is returned.
|
||||
|
||||
If `t` is of a different type, an exception of type String is thrown.
|
||||
|
||||
If `t` is null, the result is null.
|
||||
**/
|
||||
static public function getClass(t:Type)
|
||||
return t == null ? null : switch (follow(t)) {
|
||||
case TInst(c, _): c.get();
|
||||
case _: throw "Class instance expected";
|
||||
}
|
||||
|
||||
/**
|
||||
Tries to extract the enum instance stored inside `t`.
|
||||
|
||||
If `t` is an enum instance `TEnum(e,pl)`, e is returned.
|
||||
|
||||
If `t` is of a different type, an exception of type String is thrown.
|
||||
|
||||
If `t` is null, the result is null.
|
||||
**/
|
||||
static public function getEnum(t:Type)
|
||||
return t == null ? null : switch (follow(t)) {
|
||||
case TEnum(e, _): e.get();
|
||||
case _: throw "Enum instance expected";
|
||||
}
|
||||
|
||||
/**
|
||||
Applies the type parameters `typeParameters` to type `t` with the given
|
||||
types `concreteTypes`.
|
||||
|
||||
This function replaces occurrences of type parameters in `t` if they are
|
||||
part of `typeParameters`. The array index of such a type parameter is
|
||||
then used to lookup the concrete type in `concreteTypes`.
|
||||
|
||||
If `typeParameters.length` is not equal to `concreteTypes.length`, an
|
||||
exception of type `String` is thrown.
|
||||
|
||||
If `typeParameters.length` is 0, `t` is returned unchanged.
|
||||
|
||||
If either argument is `null`, the result is unspecified.
|
||||
**/
|
||||
static public function applyTypeParameters(t:Type, typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>):Type {
|
||||
if (typeParameters.length != concreteTypes.length)
|
||||
throw 'Incompatible arguments: ${typeParameters.length} type parameters and ${concreteTypes.length} concrete types';
|
||||
else if (typeParameters.length == 0)
|
||||
return t;
|
||||
#if (neko || eval)
|
||||
return @:privateAccess Context.load("apply_params", 3)(typeParameters, concreteTypes, t);
|
||||
#else
|
||||
return applyParams(typeParameters, concreteTypes, t);
|
||||
#end
|
||||
}
|
||||
|
||||
#if !neko
|
||||
private static function applyParams(typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>, t:Type):Type {
|
||||
return null;
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
Transforms `t` by calling `f` on each of its subtypes.
|
||||
|
||||
If `t` is a compound type, `f` is called on each of its components.
|
||||
|
||||
Otherwise `t` is returned unchanged.
|
||||
|
||||
The following types are considered compound:
|
||||
- TInst, TEnum, TType and TAbstract with type parameters
|
||||
- TFun
|
||||
- TAnonymous
|
||||
|
||||
If `t` or `f` are null, the result is unspecified.
|
||||
**/
|
||||
static public function map(t:Type, f:Type->Type):Type {
|
||||
return switch (t) {
|
||||
case TMono(tm):
|
||||
switch (tm.get()) {
|
||||
case null: t;
|
||||
case var t: f(t);
|
||||
}
|
||||
case TEnum(_, []) | TInst(_, []) | TType(_, []):
|
||||
t;
|
||||
case TEnum(en, tl):
|
||||
TEnum(en, tl.map(f));
|
||||
case TInst(cl, tl):
|
||||
TInst(cl, tl.map(f));
|
||||
case TType(t2, tl):
|
||||
TType(t2, tl.map(f));
|
||||
case TAbstract(a, tl):
|
||||
TAbstract(a, tl.map(f));
|
||||
case TFun(args, ret):
|
||||
TFun(args.map(function(arg) return {
|
||||
name: arg.name,
|
||||
opt: arg.opt,
|
||||
t: f(arg.t)
|
||||
}), f(ret));
|
||||
case TAnonymous(an):
|
||||
TAnonymous(@:privateAccess Context.load("map_anon_ref", 2)(an, f));
|
||||
case TDynamic(t2):
|
||||
t == t2 ? t : TDynamic(f(t2));
|
||||
case TLazy(ft):
|
||||
var ft = ft();
|
||||
var ft2 = f(ft);
|
||||
ft == ft2 ? t : ft2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Calls function `f` on each component of type `t`.
|
||||
|
||||
If `t` is not a compound type, this operation has no effect.
|
||||
|
||||
The following types are considered compound:
|
||||
- TInst, TEnum, TType and TAbstract with type parameters
|
||||
- TFun
|
||||
- TAnonymous
|
||||
|
||||
If `t` or `f` are null, the result is unspecified.
|
||||
**/
|
||||
static public function iter(t:Type, f:Type->Void):Void {
|
||||
switch (t) {
|
||||
case TMono(tm):
|
||||
var t = tm.get();
|
||||
if (t != null)
|
||||
f(t);
|
||||
case TEnum(_, tl) | TInst(_, tl) | TType(_, tl) | TAbstract(_, tl):
|
||||
for (t in tl)
|
||||
f(t);
|
||||
case TDynamic(t2):
|
||||
if (t != t2)
|
||||
f(t2);
|
||||
case TLazy(ft):
|
||||
f(ft());
|
||||
case TAnonymous(an):
|
||||
for (field in an.get().fields)
|
||||
f(field.type);
|
||||
case TFun(args, ret):
|
||||
for (arg in args)
|
||||
f(arg.t);
|
||||
f(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Converts type `t` to a human-readable String representation.
|
||||
**/
|
||||
static public function toString(t:Type):String {
|
||||
#if (neko || eval)
|
||||
return @:privateAccess Context.load("s_type", 1)(t);
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
Changes the name of the variable in the typed expression.
|
||||
**/
|
||||
static public function setVarName(t:TVar, name:String) {
|
||||
@:privateAccess Context.load("set_var_name", 2)(t, name);
|
||||
}
|
||||
|
||||
/**
|
||||
Converts type `t` to `ModuleType`.
|
||||
**/
|
||||
static public function toModuleType(t:Type):ModuleType {
|
||||
#if (neko || eval)
|
||||
return @:privateAccess Context.load("type_to_module_type", 1)(t);
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a type from the `ModuleType` argument.
|
||||
**/
|
||||
static public function fromModuleType(mt:ModuleType):Type {
|
||||
#if (neko || eval)
|
||||
return @:privateAccess Context.load("module_type_to_type", 1)(mt);
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
Resolves the field named `name` on class `c`.
|
||||
|
||||
If `isStatic` is true, the classes' static fields are checked. Otherwise
|
||||
the classes' member fields are checked.
|
||||
|
||||
If the field is found, it is returned. Otherwise if `c` has a super
|
||||
class, `findField` recursively checks that super class. Otherwise null
|
||||
is returned.
|
||||
|
||||
If any argument is null, the result is unspecified.
|
||||
**/
|
||||
static public function findField(c:ClassType, name:String, isStatic:Bool = false):Null<ClassField> {
|
||||
var field = (isStatic ? c.statics : c.fields).get().find(function(field) return field.name == name);
|
||||
return if (field != null) field; else if (c.superClass != null) findField(c.superClass.t.get(), name, isStatic); else null;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ class UnsafeReflect {
|
||||
o.__SetField(field, value, untyped __cpp__("::hx::paccAlways"));
|
||||
}
|
||||
#else
|
||||
Reflect.setProperty(o, field);
|
||||
Reflect.setProperty(o, field, value);
|
||||
#end
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class UnsafeReflect {
|
||||
return untyped func.__Run(args);
|
||||
}
|
||||
#else
|
||||
return Reflect.callMethod(o, func, args);
|
||||
return Reflect.callMethod(o, Reflect.field(o, field), args);
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package hscript.utils;
|
||||
|
||||
@:structInit
|
||||
class UsingEntry {
|
||||
public var call:Dynamic->String->Array<Dynamic>->Dynamic;
|
||||
public var fields:Array<String>;
|
||||
|
||||
public function hasField(name:String) {
|
||||
return fields.contains(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special class that handles static extension function calls.
|
||||
*
|
||||
* A static extension allows pseudo-extending
|
||||
* existing types without modifying their source.
|
||||
* In Haxe this is achieved by declaring a static method with a first argument
|
||||
* of the extending type and then bringing the defining class into context through `using`.
|
||||
*
|
||||
* Example:
|
||||
* ```haxe
|
||||
* class IntExtender {
|
||||
* static public function triple(i:Int) {
|
||||
* return i * 3;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* using IntExtender;
|
||||
*
|
||||
* trace(12.triple()); // 36
|
||||
* ```
|
||||
*
|
||||
* @see https://haxe.org/manual/lf-static-extension.html
|
||||
*/
|
||||
class UsingHandler {
|
||||
// Predefined static extension classes
|
||||
public static final defaultExtension:Map<String, UsingEntry> = [
|
||||
"StringTools" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L45
|
||||
fields: Type.getClassFields(StringTools),
|
||||
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||
if (f == "isEof") // has @:noUsing
|
||||
return null;
|
||||
return switch (Type.typeof(o)) {
|
||||
case TInt if (f == 'hex'):
|
||||
StringTools.hex(o, args[0]);
|
||||
case TClass(String):
|
||||
var field = UnsafeReflect.field(StringTools, f);
|
||||
if (UnsafeReflect.isFunction(field)) UnsafeReflect.callMethodUnsafe(StringTools, field, [o].concat(args)); else null;
|
||||
default:
|
||||
null;
|
||||
}
|
||||
}
|
||||
},
|
||||
"Lambda" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L62
|
||||
fields: Type.getClassFields(Lambda),
|
||||
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||
if (o != null && o.iterator != null) {
|
||||
var field = UnsafeReflect.field(Lambda, f);
|
||||
if (UnsafeReflect.isFunction(field)) {
|
||||
return UnsafeReflect.callMethodUnsafe(Lambda, field, [o].concat(args));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@:allow(hscript.CustomClass)
|
||||
@:allow(hscript.CustomClassHandler)
|
||||
public var usingEntries(default, null):Map<String, UsingEntry> = [];
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function registerEntry(name:String, entry:Dynamic->String->Array<Dynamic>->Dynamic, fields:Array<String>) {
|
||||
usingEntries.set(name, {call: entry, fields: fields});
|
||||
}
|
||||
|
||||
public function entryExists(name:String):Bool {
|
||||
return usingEntries.exists(name);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
bin/*
|
||||
@@ -1,9 +0,0 @@
|
||||
# Haxe project
|
||||
|
||||
This is an example Haxe project scaffolded by Visual Studio Code.
|
||||
|
||||
Without further changes the structure is following:
|
||||
|
||||
* `src/Main.hx`: Entry point Haxe source file
|
||||
* `build.hxml`: Haxe command line file used to build the project
|
||||
* `README.md`: This file
|
||||
@@ -1,25 +0,0 @@
|
||||
# Generic Haxe stuffs to make the project compile
|
||||
-cp src
|
||||
-cp ../
|
||||
-D analyzer-optimize
|
||||
-main Main
|
||||
|
||||
# Libraries (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
|
||||
# --library hxcpp-debug-server
|
||||
|
||||
# Defines (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
|
||||
--define hscriptPos
|
||||
--define HXCPP_CHECK_POINTER
|
||||
--define HXCPP_STACK_LINE
|
||||
--define HXCPP_DEBUG_LINK
|
||||
--dce no
|
||||
|
||||
# File Specific Defines
|
||||
--define linux
|
||||
|
||||
# Copying the assets from source code to bin folder
|
||||
# --cmd rm -rf bin/cpp/assets
|
||||
# --cmd cp -r assets bin/cpp/assets
|
||||
--cpp bin/cpp
|
||||
--cmd cd bin/cpp
|
||||
--cmd ./Main
|
||||
@@ -1,34 +0,0 @@
|
||||
# Generic Haxe stuffs to make the project compile
|
||||
-cp src
|
||||
-cp ../
|
||||
-D analyzer-optimize
|
||||
-main Main
|
||||
|
||||
# Libraries (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
|
||||
# --library hscript-improved
|
||||
# --library hxcpp-debug-server
|
||||
|
||||
# Defines (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
|
||||
--define hscriptPos
|
||||
--define HXCPP_CHECK_POINTER
|
||||
--define HXCPP_STACK_LINE
|
||||
--define HXCPP_DEBUG_LINK
|
||||
# -D HXCPP_M64
|
||||
# -D HXCPP_ARM64
|
||||
--dce no
|
||||
|
||||
# File Specific Defines
|
||||
--define macos
|
||||
--define mac
|
||||
|
||||
--macro keep('IntIterator')
|
||||
# --macro hscript.macros.UsingHandler.init()
|
||||
# --macro hscript.macros.ClassExtendMacro.init()
|
||||
|
||||
|
||||
# Copying the assets from source code to bin folder
|
||||
# --cmd rm -rf bin/cpp/assets
|
||||
# --cmd cp -r assets bin/cpp/assets
|
||||
--cpp bin/cpp
|
||||
--cmd cd bin/cpp
|
||||
--cmd ./Main
|
||||
@@ -1,74 +0,0 @@
|
||||
package;
|
||||
|
||||
import hscript.Interp;
|
||||
import hscript.Expr;
|
||||
|
||||
@:access(hscript.Interp)
|
||||
@:access(hscript.Parser)
|
||||
class HScriptRunner {
|
||||
public var interp:Interp;
|
||||
public var headerCode:String = "";
|
||||
public var tailCode:String = "";
|
||||
|
||||
public var clearPrevious:Bool = true;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function getNewInterp() {
|
||||
var interp = Util.getInterp();
|
||||
interp.errorHandler = Util.errorHandler;
|
||||
return interp;
|
||||
}
|
||||
|
||||
public function setup() {
|
||||
interp = getNewInterp();
|
||||
}
|
||||
public function run() {}
|
||||
public function teardown() {}
|
||||
|
||||
private var lastExpr:Expr;
|
||||
|
||||
public function execute(script:String):Dynamic {
|
||||
var interp = clearPrevious ? getNewInterp() : this.interp;
|
||||
lastExpr = Util.parse(headerCode + script + tailCode);
|
||||
if(lastExpr == null)
|
||||
return "ERROR";
|
||||
if (clearPrevious)
|
||||
return interp.execute(lastExpr);
|
||||
else
|
||||
return interp.exprReturn(lastExpr);
|
||||
}
|
||||
|
||||
public function executeWithVars(script:String, vars:Dynamic):Dynamic {
|
||||
var interp = clearPrevious ? getNewInterp() : this.interp;
|
||||
lastExpr = Util.parse(headerCode + script + tailCode);
|
||||
if(lastExpr == null)
|
||||
return "ERROR";
|
||||
for(v in Reflect.fields(vars))
|
||||
interp.variables.set(v, Reflect.field(vars, v));
|
||||
if (clearPrevious)
|
||||
return interp.execute(lastExpr);
|
||||
else
|
||||
return interp.exprReturn(lastExpr);
|
||||
}
|
||||
|
||||
public function executeUnsafe(script:String):Dynamic {
|
||||
var interp = clearPrevious ? getNewInterp() : this.interp;
|
||||
lastExpr = Util.parseUnsafe(headerCode + script + tailCode);
|
||||
if (clearPrevious)
|
||||
return interp.execute(lastExpr);
|
||||
else
|
||||
return interp.exprReturn(lastExpr);
|
||||
}
|
||||
|
||||
public function executeWithVarsUnsafe(script:String, vars:Dynamic):Dynamic {
|
||||
var interp = clearPrevious ? getNewInterp() : this.interp;
|
||||
lastExpr = Util.parseUnsafe(headerCode + script + tailCode);
|
||||
for(v in Reflect.fields(vars))
|
||||
interp.variables.set(v, Reflect.field(vars, v));
|
||||
if (clearPrevious)
|
||||
return interp.execute(lastExpr);
|
||||
else
|
||||
return interp.exprReturn(lastExpr);
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#if BENCHMARK
|
||||
import benchmark.*;
|
||||
#else
|
||||
import tests.*;
|
||||
#end
|
||||
|
||||
class Main {
|
||||
public static var SHOW_KNOWN_BUGS:Bool = false;
|
||||
|
||||
static function main() {
|
||||
#if BENCHMARK
|
||||
Sys.println("Running benchmark");
|
||||
|
||||
//new Benchmark("Test", 1000);
|
||||
var haxeTotalTime:Float = 0;
|
||||
var hscriptTotalTime:Float = 0;
|
||||
|
||||
var haxeTimes:Array<Float> = [];
|
||||
var hscriptTimes:Array<Float> = [];
|
||||
|
||||
var iterations:Int = 10;
|
||||
for (i in 0...iterations) {
|
||||
var benchmark:TestBenchmark = new TestBenchmark();
|
||||
|
||||
haxeTimes.push(benchmark.haxeTotalTime);
|
||||
hscriptTimes.push(benchmark.hscriptTotalTime);
|
||||
|
||||
haxeTotalTime += benchmark.haxeTotalTime;
|
||||
hscriptTotalTime += benchmark.hscriptTotalTime;
|
||||
}
|
||||
|
||||
haxeTimes.sort((a, b) -> return a > b ? 1 : -1);
|
||||
hscriptTimes.sort((a, b) -> return a > b ? 1 : -1);
|
||||
|
||||
var slowestHaxeTime:Float = haxeTimes[haxeTimes.length-1];
|
||||
var slowestHscriptTime:Float = hscriptTimes[hscriptTimes.length-1];
|
||||
var fastestHaxeTime:Float = haxeTimes[0];
|
||||
var fastestHscriptTime:Float = hscriptTimes[0];
|
||||
|
||||
var haxeWon = hscriptTotalTime > haxeTotalTime;
|
||||
Sys.println('${haxeWon ? "Haxe" : "Hscript"} was faster overall (Faster by: ${Util.roundWith((haxeWon ? hscriptTotalTime/haxeTotalTime : haxeTotalTime/hscriptTotalTime), 100)}x)');
|
||||
Sys.println('Haxe average time: ${Util.convertToReadableTime(haxeTotalTime/iterations)} (Highest: ${Util.convertToReadableTime(slowestHaxeTime)}) (Lowest: ${Util.convertToReadableTime(fastestHaxeTime)})');
|
||||
Sys.println('Hscript average time: ${Util.convertToReadableTime(hscriptTotalTime/iterations)} (Highest: ${Util.convertToReadableTime(slowestHscriptTime)}) (Lowest: ${Util.convertToReadableTime(fastestHscriptTime)})');
|
||||
#else
|
||||
Sys.println("Beginning tests");
|
||||
if(!Main.SHOW_KNOWN_BUGS) {
|
||||
Sys.println("Hiding known bugs [TEMPORARY]");
|
||||
}
|
||||
runTest("Array", new ArrayCase());
|
||||
runTest("BinOp", new BinOpCase());
|
||||
runTest("Enum", new EnumCase());
|
||||
runTest("EvalOrder", new EvalOrderCase());
|
||||
runTest("Error", new ErrorCase());
|
||||
runTest("Float", new FloatCase());
|
||||
runTest("IntIterator", new IntIteratorCase());
|
||||
runTest("Lambda", new LambdaCase());
|
||||
runTest("List", new ListCase());
|
||||
runTest("Math", new MathCase());
|
||||
runTest("Map", new MapCase());
|
||||
runTest("Misc", new MiscCase());
|
||||
runTest("Reflect", new ReflectCase());
|
||||
runTest("Regex", new RegexCase());
|
||||
runTest("Std", new StdCase());
|
||||
runTest("String", new StringCase());
|
||||
runTest("StringBuf", new StringBufCase());
|
||||
runTest("StringTools", new StringToolsCase());
|
||||
runTest("SwitchStatement", new SwitchCase());
|
||||
// TODO: UnicodeCase.hx?
|
||||
// TODO: UnicodeStringCase.hx?
|
||||
runTest("Final", new FinalCase());
|
||||
Util.printTestResults();
|
||||
#end
|
||||
}
|
||||
|
||||
#if !BENCHMARK
|
||||
static function runTest(name:String, test:TestCase) {
|
||||
Util.startUnitTest(name);
|
||||
test.setup();
|
||||
test.run();
|
||||
test.teardown();
|
||||
Util.endUnitTest();
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
import hscript.Expr.Error;
|
||||
import hscript.Printer;
|
||||
import haxe.Constraints.IMap;
|
||||
import haxe.EnumTools.EnumValueTools;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class Util {
|
||||
static inline function isNull(a:Dynamic):Bool {
|
||||
return Type.enumEq(Type.typeof(a), TNull);
|
||||
}
|
||||
|
||||
static inline function isFunction(a:Dynamic):Bool {
|
||||
return Type.enumEq(Type.typeof(a), TFunction);
|
||||
}
|
||||
|
||||
// TODO: check this for bugs
|
||||
// Code from https://github.com/elnabo/equals/blob/master/src/equals/Equal.hx, (MIT License), but updated to work with haxe 4
|
||||
public static function deepEqual<T> (a:T, b:T) : Bool {
|
||||
if (a == b) { return true; } // if physical equality
|
||||
if (isNull(a) || isNull(b)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (Type.typeof(a)) {
|
||||
case TNull, TInt, TBool, TUnknown:
|
||||
return a == b;
|
||||
case TFloat:
|
||||
return Math.isNaN(cast a) && Math.isNaN(cast b); // only valid true result remaining
|
||||
case TFunction:
|
||||
return Reflect.compareMethods(a, b); // only physical equality can be tested for function
|
||||
case TEnum(_):
|
||||
if (EnumValueTools.getIndex(cast a) != EnumValueTools.getIndex(cast b)) {
|
||||
return false;
|
||||
}
|
||||
var a_args = EnumValueTools.getParameters(cast a);
|
||||
var b_args = EnumValueTools.getParameters(cast b);
|
||||
return deepEqual(a_args, b_args);
|
||||
case TClass(_):
|
||||
if ((a is String) && (b is String)) {
|
||||
return a == b;
|
||||
}
|
||||
if ((a is Array) && (b is Array)) {
|
||||
var a = cast(a, Array<Dynamic>);
|
||||
var b = cast(b, Array<Dynamic>);
|
||||
if (a.length != b.length) { return false; }
|
||||
for (i in 0...a.length) {
|
||||
if (!deepEqual(a[i], b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((a is IMap) && (b is IMap)) {
|
||||
var a = cast(a, IMap<Dynamic, Dynamic>);
|
||||
var b = cast(b, IMap<Dynamic, Dynamic>);
|
||||
var a_keys = [ for (key in a.keys()) key ];
|
||||
var b_keys = [ for (key in b.keys()) key ];
|
||||
a_keys.sort(Reflect.compare);
|
||||
b_keys.sort(Reflect.compare);
|
||||
if (!deepEqual(a_keys, b_keys)) { return false; }
|
||||
for (key in a_keys) {
|
||||
if (!deepEqual(a.get(key), b.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((a is Date) && (b is Date)) {
|
||||
return cast(a, Date).getTime() == cast(b, Date).getTime();
|
||||
}
|
||||
|
||||
if ((a is haxe.io.Bytes) && (b is haxe.io.Bytes)) {
|
||||
return deepEqual(cast(a, haxe.io.Bytes).getData(), cast(b, haxe.io.Bytes).getData());
|
||||
}
|
||||
|
||||
case TObject:
|
||||
}
|
||||
|
||||
for (field in Reflect.fields(a)) {
|
||||
var pa = Reflect.field(a, field);
|
||||
var pb = Reflect.field(b, field);
|
||||
if (isFunction(pa)) {
|
||||
// ignore function as only physical equality can be tested, unless null
|
||||
if (isNull(pa) != isNull(pb)) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!deepEqual(pa, pb)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static inline function passed() {
|
||||
passedTestUnits++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static inline function failed() {
|
||||
failedTestUnits++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static function assert(value:Bool, message:String, ?pos:haxe.PosInfos) {
|
||||
if (value) {
|
||||
return passed();
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message);
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
return failed();
|
||||
}
|
||||
}
|
||||
|
||||
public static function assertEq(value:Dynamic, expected:Dynamic, message:String, ?pos:haxe.PosInfos) {
|
||||
var equals = deepEqual(value, expected);
|
||||
var _passed = equals;
|
||||
|
||||
if (_passed) {
|
||||
return passed();
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message + " Expected: " + expected + " Got: " + value);
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
return failed();
|
||||
}
|
||||
}
|
||||
|
||||
public static function assertEqPrintable(value:Dynamic, expected:Dynamic, message:String, ?pos:haxe.PosInfos) {
|
||||
var equals = deepEqual(value, expected);
|
||||
var _passed = equals;
|
||||
|
||||
if (_passed) {
|
||||
return passed();
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message + " Expected: " + Printer.getEscapedString(expected) + " Got: " + Printer.getEscapedString(value));
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
return failed();
|
||||
}
|
||||
}
|
||||
|
||||
public static function assertNeq(value:Dynamic, expected:Dynamic, message:String, ?pos:haxe.PosInfos) {
|
||||
var equals = deepEqual(value, expected);
|
||||
var _passed = !equals;
|
||||
|
||||
// WARNING THIS MIGHT NOT WORK
|
||||
|
||||
if (_passed) {
|
||||
return passed();
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message + " Expected: " + expected + " Got: " + value);
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
return failed();
|
||||
}
|
||||
}
|
||||
|
||||
static var currentTestPath:Array<String> = [];
|
||||
static var totalTestUnits:Int = 0;
|
||||
static var passedTestUnits:Int = 0;
|
||||
static var failedTestUnits:Int = 0;
|
||||
static var skippedKnownBugs:Int = 0;
|
||||
|
||||
public static function runKnownBug(name:String, func:Void->Void) {
|
||||
if (Main.SHOW_KNOWN_BUGS) {
|
||||
Sys.println("Running known bug: " + name);
|
||||
func();
|
||||
} else {
|
||||
skippedKnownBugs++;
|
||||
}
|
||||
}
|
||||
|
||||
public static function startUnitTest(path:String) {
|
||||
Sys.println("Running unit tests in " + path);
|
||||
currentTestPath.push(path);
|
||||
totalTestUnits++;
|
||||
}
|
||||
|
||||
public static function endUnitTest() {
|
||||
var path = currentTestPath.pop();
|
||||
//Sys.println("Finished unit tests " + path);
|
||||
}
|
||||
|
||||
public static function printTestResults() {
|
||||
Sys.println(Util.getTitle('RESULTS'));
|
||||
Sys.println("Total Units: " + totalTestUnits);
|
||||
Sys.println("Total tests passed: " + passedTestUnits);
|
||||
Sys.println("Total tests failed: " + failedTestUnits);
|
||||
if(skippedKnownBugs > 0)
|
||||
Sys.println("Skipped known bugs: " + skippedKnownBugs);
|
||||
//Sys.println("Finished unit tests " + currentTestPath.pop());
|
||||
Sys.println(Util.getTitle('RESULTS'));
|
||||
}
|
||||
|
||||
public static function parse(str:String) {
|
||||
var p = new Parser();
|
||||
p.allowTypes = true;
|
||||
p.allowMetadata = true;
|
||||
p.allowJSON = true;
|
||||
var result = null;
|
||||
try {
|
||||
result = p.parseString(str);
|
||||
} catch (e:Dynamic) {
|
||||
Sys.println("## Error parsing: " + str);
|
||||
Sys.println("## Error: " + e);
|
||||
// Print stack trace
|
||||
var stack = haxe.CallStack.toString(haxe.CallStack.exceptionStack());
|
||||
Sys.println("## Stack trace: " + stack);
|
||||
Sys.exit(1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string without checking for errors
|
||||
*/
|
||||
public static function parseUnsafe(str:String) {
|
||||
var p = new Parser();
|
||||
p.allowTypes = true;
|
||||
p.allowMetadata = true;
|
||||
p.allowJSON = true;
|
||||
return p.parseString(str);
|
||||
}
|
||||
|
||||
public static var defaultImport = true;
|
||||
|
||||
public static function getInterp() {
|
||||
var interp = new Interp();
|
||||
//interp.importEnabled = true;
|
||||
//interp.allowStaticVariables = true;
|
||||
//interp.allowPublicVariables = true;
|
||||
if(defaultImport) {
|
||||
interp.variables.set("Math", Math);
|
||||
interp.variables.set("Std", Std);
|
||||
interp.variables.set("Type", Type);
|
||||
interp.variables.set("StringTools", StringTools);
|
||||
}
|
||||
return interp;
|
||||
}
|
||||
|
||||
public static inline function getTime():Float {
|
||||
return untyped __global__.__time_stamp();
|
||||
}
|
||||
|
||||
// expandScientificNotation but its WAY too long to write out
|
||||
public static function exScienceN(value:Float):String {
|
||||
var parts = Std.string(value).split("e");
|
||||
var coefficient = Std.parseFloat(parts[0]);
|
||||
var exponent = parts.length > 1 ? Std.parseInt(parts[1]) : 0;
|
||||
var result = "";
|
||||
|
||||
if (exponent > 0) {
|
||||
result += StringTools.replace(Std.string(coefficient), ".", "");
|
||||
var decimalLength = Std.string(coefficient).split(".")[1].length;
|
||||
var additionalZeros:Int = Std.int(Math.abs(exponent - decimalLength));
|
||||
result += StringTools.lpad("", "0", additionalZeros); // repeat
|
||||
} else {
|
||||
result += "0.";
|
||||
var leadingZeros:Int = Std.int(Math.abs(exponent) - 1);
|
||||
result += StringTools.lpad("", "0", leadingZeros); // repeat
|
||||
result += StringTools.replace(Std.string(coefficient), ".", "");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static function convertToReadableTime(seconds:Float) {
|
||||
if (seconds >= 1) return seconds + " s";
|
||||
var milliseconds = seconds * 1000; // 1 second = 1,000 ms
|
||||
if (milliseconds >= 1) return milliseconds + " ms";
|
||||
var microseconds = seconds * 1000000; // 1 second = 1,000,000 μs
|
||||
if (microseconds >= 1) return microseconds + " μs";
|
||||
var nanoseconds = seconds * 1000000000; // 1 second = 1,000,000,000 ns
|
||||
return nanoseconds + " ns";
|
||||
}
|
||||
|
||||
public static function errorHandler(error:Error) {
|
||||
#if hscriptPos
|
||||
var fileName = error.origin;
|
||||
var fn = '$fileName:${error.line}: ';
|
||||
#else
|
||||
var fn = '';
|
||||
#end
|
||||
var err = Std.string(error);
|
||||
if (err.startsWith(fn)) err = err.substr(fn.length);
|
||||
|
||||
Sys.println("ERROR: " + fn + err);
|
||||
//Logs.traceColored([
|
||||
// Logs.logText(fn, GREEN),
|
||||
// Logs.logText(err, RED)
|
||||
//], ERROR);
|
||||
}
|
||||
|
||||
public static function deepCompareArrays(a1: Array<Dynamic>, a2: Array<Dynamic>): Bool {
|
||||
if (a1.length != a2.length)
|
||||
return false;
|
||||
|
||||
for (i in 0...a1.length) {
|
||||
var item1 = a1[i];
|
||||
var item2 = a2[i];
|
||||
|
||||
if (Std.isOfType(item1, Array) && Std.isOfType(item2, Array)) {
|
||||
if (!deepCompareArrays(item1, item2))
|
||||
return false;
|
||||
} else if (item1 != item2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function roundDecimal(Value:Float, Precision:Int):Float {
|
||||
var mult:Float = 1;
|
||||
for (i in 0...Precision)
|
||||
mult *= 10;
|
||||
return Math.fround(Value * mult) / mult;
|
||||
}
|
||||
|
||||
public inline static function roundWith(Value:Float, Mult:Int):Float {
|
||||
return Math.fround(Value * Mult) / Mult;
|
||||
}
|
||||
|
||||
public static function getTitle(title:String, ?dashsLen:Int = 46) {
|
||||
var l = StringTools.lpad("", "-", Std.int((dashsLen - title.length - 2)/2));
|
||||
return l + ' $title ' + l;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package benchmark;
|
||||
|
||||
import hscript.Expr;
|
||||
|
||||
class Benchmark extends HScriptRunner {
|
||||
public var haxeTimes:Array<Float> = [];
|
||||
public var haxeTotalTime:Float = 0;
|
||||
|
||||
public var hscriptTimes:Array<Float> = [];
|
||||
public var hscriptTotalTime:Float = 0;
|
||||
|
||||
public function new(name:String, iterations:Int) {
|
||||
super();
|
||||
doBenchmark(name, iterations);
|
||||
}
|
||||
|
||||
public function doBenchmark(name:String, iterations:Int) {
|
||||
haxeTimes = cast new haxe.ds.Vector<Float>(iterations);
|
||||
hscriptTimes = cast new haxe.ds.Vector<Float>(iterations);
|
||||
|
||||
for (i in 0...iterations) {
|
||||
reset();
|
||||
var haxeStartTime:Float = Util.getTime();
|
||||
haxeBenchmark();
|
||||
var haxeEndTime:Float = Util.getTime();
|
||||
haxeTimes[i] = haxeEndTime-haxeStartTime;
|
||||
|
||||
reset();
|
||||
var hscriptStartTime:Float = Util.getTime();
|
||||
hscriptBenchmark();
|
||||
var hscriptEndTime:Float = Util.getTime();
|
||||
hscriptTimes[i] = hscriptEndTime-hscriptStartTime;
|
||||
}
|
||||
|
||||
haxeTimes.sort(Reflect.compare);
|
||||
hscriptTimes.sort(Reflect.compare);
|
||||
|
||||
for (time in haxeTimes) haxeTotalTime += time;
|
||||
for (time in hscriptTimes) hscriptTotalTime += time;
|
||||
|
||||
Sys.println(Util.getTitle('$name BENCHMARK'));
|
||||
|
||||
if ((haxeTotalTime == 0 || hscriptTotalTime == 0) || (haxeTimes.length <= 0 || hscriptTimes.length <= 0)) {
|
||||
Sys.println('BENCHMARK UNNOTICABLE, TOOK 0 SECONDS');
|
||||
} else {
|
||||
var haxeWon = hscriptTotalTime > haxeTotalTime;
|
||||
Sys.println('${haxeWon ? "Haxe" : "Hscript"} was faster overall (Faster by: ${Util.roundWith((haxeWon ? hscriptTotalTime/haxeTotalTime : haxeTotalTime/hscriptTotalTime), 100)}x)');
|
||||
Sys.println('Haxe average time: ${Util.convertToReadableTime(haxeTotalTime/iterations)} (Highest: ${haxeTimes[haxeTimes.length-1]})');
|
||||
Sys.println('Hscript average time: ${Util.convertToReadableTime(hscriptTotalTime/iterations)} (Highest: ${hscriptTimes[haxeTimes.length-1]})');
|
||||
}
|
||||
|
||||
Sys.println(Util.getTitle('$name BENCHMARK'));
|
||||
}
|
||||
|
||||
public function reset() {}
|
||||
|
||||
public var expr:Expr;
|
||||
|
||||
public inline function cacheExpr(script:String) {
|
||||
interp = getNewInterp();
|
||||
interp.variables.set("self", this);
|
||||
interp.scriptObject = this;
|
||||
expr = Util.parse(headerCode + script + tailCode);
|
||||
}
|
||||
|
||||
public override function execute(script:String):Dynamic {
|
||||
if (expr == null)
|
||||
cacheExpr(script);
|
||||
return interp.execute(expr);
|
||||
}
|
||||
|
||||
public function haxeBenchmark() {}
|
||||
public function hscriptBenchmark() {}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package benchmark;
|
||||
|
||||
@:dce(off)
|
||||
class TestBenchmark extends Benchmark {
|
||||
public function new() {
|
||||
super("Test", 10000);
|
||||
}
|
||||
|
||||
//var hscript = "var a:Array<Float> = []; for (i in 0...1000) a.push(i * 2 + 1 / 6); if(true == true) a.push(1);";
|
||||
var hscript = "
|
||||
var a:Array<Float> = [];
|
||||
for(i in 0...1000) {
|
||||
switch(5) {
|
||||
case true: a.push(1);
|
||||
default: a.push(i / 1);
|
||||
}
|
||||
}
|
||||
if(('a' == 'a') ? true : false) a.push(1);
|
||||
if(true == true)
|
||||
a.push(1);";
|
||||
|
||||
function test() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
var aaa = null;
|
||||
|
||||
public override function reset() {
|
||||
super.reset();
|
||||
aaa = {
|
||||
test: test
|
||||
};
|
||||
if(expr == null)
|
||||
cacheExpr(hscript);
|
||||
interp.variables.remove("a");
|
||||
//interp.variables.set("aaa", aaa);
|
||||
interp.variables.set("test", test);
|
||||
}
|
||||
|
||||
public override function haxeBenchmark() {
|
||||
var a:Array<Float> = [];
|
||||
//for (i in 0...1000) a.push(i * 2 + 1 / 6);
|
||||
//for (i in 0...1000) a.push(i / 2 + 3 / 6);
|
||||
for(i in 0...1000) {
|
||||
switch(5) {
|
||||
case 0: a.push(1);
|
||||
default: a.push(i / 1);
|
||||
}
|
||||
}
|
||||
if(('a' == 'a') ? true : false) a.push(1);
|
||||
if(true == true) a.push(1);
|
||||
}
|
||||
|
||||
public override function hscriptBenchmark() {
|
||||
interp.execute(expr);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import hscript.Interp;
|
||||
import hscript.Parser;
|
||||
|
||||
import Util;
|
||||
@@ -1,19 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class ArrayCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function run() {
|
||||
assertEq("[].length", 0);
|
||||
assertEq("[1].length", 1);
|
||||
assertEq("[1,2,3].length", 3);
|
||||
assertEq("var a = [];\na[4] = 1;\na.length", 5);
|
||||
assertEq("var a = [];\na[4] = 1;\na[a.length] = 1;\na.length", 6);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class BinOpCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
|
||||
headerCode = "
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var c = 3;
|
||||
";
|
||||
|
||||
//tailCode = "";
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var c = 3;
|
||||
|
||||
assertEq("a + b", a + b);
|
||||
assertEq("a - b", a - b);
|
||||
assertEq("a * b", a * b);
|
||||
assertEq("a / b", a / b);
|
||||
assertEq("a % b", a % b);
|
||||
assertEq("a & b", a & b);
|
||||
assertEq("a | b", a | b);
|
||||
assertEq("a ^ b", a ^ b);
|
||||
assertEq("5 ^ 3", 5 ^ 3);
|
||||
assertEq("a << b", a << b);
|
||||
assertEq("a >> b", a >> b);
|
||||
assertEq("a >>> b", a >>> b);
|
||||
assertEq("a == b", a == b);
|
||||
assertEq("a != b", a != b);
|
||||
assertEq("a >= b", a >= b);
|
||||
assertEq("a <= b", a <= b);
|
||||
assertEq("a > b", a > b);
|
||||
assertEq("a < b", a < b);
|
||||
//assertEq("a || b", a || b);
|
||||
//assertEq("a && b", a && b);
|
||||
//assertEq("a is b", false);
|
||||
|
||||
// Order of operations
|
||||
assertEq("a + b * c", a + b * c);
|
||||
assertEq("a * b + c", a * b + c);
|
||||
assertEq("a * (b + c)", a * (b + c));
|
||||
assertEq("(a + b) * c", (a + b) * c);
|
||||
assertEq("a / b / c", a / b / c);
|
||||
assertEq("a % b % c", a % b % c);
|
||||
assertEq("a & b & c", a & b & c);
|
||||
assertEq("a | b | c", a | b | c);
|
||||
assertEq("a ^ b ^ c", a ^ b ^ c);
|
||||
assertEq("a << b << c", a << b << c);
|
||||
assertEq("a >> b >> c", a >> b >> c);
|
||||
assertEq("a >>> b >>> c", a >>> b >>> c);
|
||||
|
||||
// Precedence
|
||||
assertEq("a + b + c", a + b + c);
|
||||
assertEq("a + b - c", a + b - c);
|
||||
assertEq("a * b / c", a * b / c);
|
||||
assertEq("a / b * c", a / b * c);
|
||||
assertEq("a % b | c", a % b | c);
|
||||
assertEq("a & b ^ c", a & b ^ c);
|
||||
assertEq("a << b >> c", a << b >> c);
|
||||
assertEq("a >>> b << c", a >>> b << c);
|
||||
|
||||
|
||||
headerCode = "
|
||||
var a = null;
|
||||
var b = 'hello';
|
||||
var c = 'world';
|
||||
var d = '!';
|
||||
";
|
||||
|
||||
var a = null;
|
||||
var b = 'hello';
|
||||
var c = 'world';
|
||||
var d = '!';
|
||||
|
||||
assertEq("a + b", a + b);
|
||||
|
||||
#if (haxe >= "4.3.0")
|
||||
assertEq("a ?? b", a ?? b);
|
||||
assertEq("a ?? b ?? c", a ?? b ?? c);
|
||||
assertEq("a ?? b ?? c ?? d", a ?? b ?? c ?? d);
|
||||
#else
|
||||
Sys.println("Tests are inaccurate with Haxe 4.2.x");
|
||||
assertEq("a ?? b", nc(a, b));
|
||||
assertEq("a ?? b ?? c", nc(a, nc(b, c)));
|
||||
assertEq("a ?? b ?? c ?? d", nc(a, nc(b, nc(c, d))));
|
||||
#end
|
||||
|
||||
var tests:Array<Array<Dynamic>> = [
|
||||
[null, "null"],
|
||||
[{}, "{}"],
|
||||
[{a: 1}, "{a: 1}"],
|
||||
[{a: {b: 1}}, "{a: {b: 1}}"],
|
||||
[{a: {b: {c: 1}}}, "{a: {b: {c: 1}}}"],
|
||||
[{a: {b: {c: {d: 1}}}}, "{a: {b: {c: {d: 1}}}}"]
|
||||
];
|
||||
|
||||
for(code in tests) {
|
||||
headerCode = 'var a = ${code[1]};';
|
||||
var a = code[0];
|
||||
|
||||
#if (haxe >= "4.3.0")
|
||||
assertEq("a?.b", a?.b);
|
||||
assertEq("a?.b?.c", a?.b?.c);
|
||||
assertEq("a?.b?.c?.d", a?.b?.c?.d);
|
||||
#else
|
||||
assertEq("a?.b", nf(a, b));
|
||||
assertEq("a?.b?.c", nf(nf(a, b), c));
|
||||
assertEq("a?.b?.c?.d", nf(nf(nf(a, b), c), d));
|
||||
#end
|
||||
}
|
||||
|
||||
headerCode = "
|
||||
var a = null;
|
||||
var b = 'hello';
|
||||
";
|
||||
|
||||
var a = null;
|
||||
var b = 'hello';
|
||||
|
||||
#if (haxe >= "4.3.0")
|
||||
a ??= b;
|
||||
assertEq("a ??"+"= b; a", a);
|
||||
#else
|
||||
if(a == null) a = b;
|
||||
assertEq("a ??"+"= b; a", a);
|
||||
#end
|
||||
|
||||
headerCode = "
|
||||
var a = 'test';
|
||||
var b = 'hello';
|
||||
";
|
||||
|
||||
var a = 'test';
|
||||
var b = 'hello';
|
||||
|
||||
#if (haxe >= "4.3.0")
|
||||
a ??= b;
|
||||
assertEq("a ??"+"= b; a", a);
|
||||
#else
|
||||
if(a == null) a = b;
|
||||
assertEq("a ??"+"= b; a", a);
|
||||
#end
|
||||
}
|
||||
|
||||
inline function nc(a:Dynamic, b:Dynamic):Dynamic {
|
||||
return (a == null) ? b : a;
|
||||
}
|
||||
|
||||
inline function nf(a:Dynamic, b:String):Dynamic {
|
||||
return (a == null) ? null : Reflect.field(a, b);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class EnumCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
var importEnabled = true;
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("assertEq", Util.assertEq);
|
||||
if(importEnabled)
|
||||
interp.variables.set("SomeEnum", SomeEnum);
|
||||
interp.variables.set("Type", Type);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
assertEq("SomeEnum.NoArguments;", SomeEnum.NoArguments);
|
||||
assertEq("SomeEnum.OneArgument('foo');", SomeEnum.OneArgument("foo"));
|
||||
assertEq("SomeEnum.TwoArguments('foo', 'bar');", SomeEnum.TwoArguments("foo", "bar"));
|
||||
|
||||
assertEq("Type.enumEq(SomeEnum.NoArguments, SomeEnum.NoArguments);", Type.enumEq(SomeEnum.NoArguments, SomeEnum.NoArguments));
|
||||
assertEq("Type.enumEq(SomeEnum.NoArguments, SomeEnum.OneArgument('foo'));", Type.enumEq(SomeEnum.NoArguments, SomeEnum.OneArgument("foo")));
|
||||
assertEq("Type.enumEq(SomeEnum.OneArgument('foo'), SomeEnum.OneArgument('foo'));", Type.enumEq(SomeEnum.OneArgument("foo"), SomeEnum.OneArgument("foo")));
|
||||
assertEq("Type.enumEq(SomeEnum.OneArgument('foo'), SomeEnum.TwoArguments('foo', 'bar'));", Type.enumEq(SomeEnum.OneArgument("foo"), SomeEnum.TwoArguments("foo", "bar")));
|
||||
assertEq("Type.enumEq(SomeEnum.TwoArguments('foo', 'bar'), SomeEnum.TwoArguments('foo', 'bar'));", Type.enumEq(SomeEnum.TwoArguments("foo", "bar"), SomeEnum.TwoArguments("foo", "bar")));
|
||||
assertEq("Type.enumEq(SomeEnum.TwoArguments('foo', 'bar'), SomeEnum.NoArguments);", Type.enumEq(SomeEnum.TwoArguments("foo", "bar"), SomeEnum.NoArguments));
|
||||
|
||||
importEnabled = false;
|
||||
headerCode = "import tests.EnumCase.SomeEnum;";
|
||||
|
||||
assertEq("SomeEnum.NoArguments;", SomeEnum.NoArguments);
|
||||
assertEq("SomeEnum.OneArgument('foo');", SomeEnum.OneArgument("foo"));
|
||||
assertEq("SomeEnum.TwoArguments('foo', 'bar');", SomeEnum.TwoArguments("foo", "bar"));
|
||||
|
||||
assertEq("Type.enumEq(SomeEnum.NoArguments, SomeEnum.NoArguments);", Type.enumEq(SomeEnum.NoArguments, SomeEnum.NoArguments));
|
||||
assertEq("Type.enumEq(SomeEnum.NoArguments, SomeEnum.OneArgument('foo'));", Type.enumEq(SomeEnum.NoArguments, SomeEnum.OneArgument("foo")));
|
||||
assertEq("Type.enumEq(SomeEnum.OneArgument('foo'), SomeEnum.OneArgument('foo'));", Type.enumEq(SomeEnum.OneArgument("foo"), SomeEnum.OneArgument("foo")));
|
||||
assertEq("Type.enumEq(SomeEnum.OneArgument('foo'), SomeEnum.TwoArguments('foo', 'bar'));", Type.enumEq(SomeEnum.OneArgument("foo"), SomeEnum.TwoArguments("foo", "bar")));
|
||||
assertEq("Type.enumEq(SomeEnum.TwoArguments('foo', 'bar'), SomeEnum.TwoArguments('foo', 'bar'));", Type.enumEq(SomeEnum.TwoArguments("foo", "bar"), SomeEnum.TwoArguments("foo", "bar")));
|
||||
assertEq("Type.enumEq(SomeEnum.TwoArguments('foo', 'bar'), SomeEnum.NoArguments);", Type.enumEq(SomeEnum.TwoArguments("foo", "bar"), SomeEnum.NoArguments));
|
||||
|
||||
headerCode = "import tests.SomeEnum;";
|
||||
|
||||
assertEq("SomeEnum.NoArguments;", SomeEnum.NoArguments);
|
||||
assertEq("SomeEnum.OneArgument('foo');", SomeEnum.OneArgument("foo"));
|
||||
assertEq("SomeEnum.TwoArguments('foo', 'bar');", SomeEnum.TwoArguments("foo", "bar"));
|
||||
|
||||
assertEq("Type.enumEq(SomeEnum.NoArguments, SomeEnum.NoArguments);", Type.enumEq(SomeEnum.NoArguments, SomeEnum.NoArguments));
|
||||
assertEq("Type.enumEq(SomeEnum.NoArguments, SomeEnum.OneArgument('foo'));", Type.enumEq(SomeEnum.NoArguments, SomeEnum.OneArgument("foo")));
|
||||
assertEq("Type.enumEq(SomeEnum.OneArgument('foo'), SomeEnum.OneArgument('foo'));", Type.enumEq(SomeEnum.OneArgument("foo"), SomeEnum.OneArgument("foo")));
|
||||
assertEq("Type.enumEq(SomeEnum.OneArgument('foo'), SomeEnum.TwoArguments('foo', 'bar'));", Type.enumEq(SomeEnum.OneArgument("foo"), SomeEnum.TwoArguments("foo", "bar")));
|
||||
assertEq("Type.enumEq(SomeEnum.TwoArguments('foo', 'bar'), SomeEnum.TwoArguments('foo', 'bar'));", Type.enumEq(SomeEnum.TwoArguments("foo", "bar"), SomeEnum.TwoArguments("foo", "bar")));
|
||||
assertEq("Type.enumEq(SomeEnum.TwoArguments('foo', 'bar'), SomeEnum.NoArguments);", Type.enumEq(SomeEnum.TwoArguments("foo", "bar"), SomeEnum.NoArguments));
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
enum SomeEnum {
|
||||
NoArguments;
|
||||
OneArgument(arg:String);
|
||||
TwoArguments(arg1:String, arg2:String);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class ErrorCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
Sys.println("TODO: write tests for errors");
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class EvalOrderCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
|
||||
headerCode = '
|
||||
function func(i1:Dynamic, i2:Dynamic, i3:Dynamic) {
|
||||
return i1 + ";" + i2 + ";" + i3;
|
||||
}
|
||||
';
|
||||
|
||||
//tailCode = "";
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var a = 1;
|
||||
var b = 2;
|
||||
var c = 3;
|
||||
|
||||
function func(i1:Dynamic, i2:Dynamic, i3:Dynamic) {
|
||||
return i1 + ";" + i2 + ";" + i3;
|
||||
}
|
||||
|
||||
clearPrevious = true;
|
||||
|
||||
var i = 0;
|
||||
assertEq("var i = 0; func(i++, i++, i++)", func(i++, i++, i++));
|
||||
var i = 0;
|
||||
assertEq("var i = 0; [i++, i++, i++].join(';')", [i++, i++, i++].join(";"));
|
||||
|
||||
var i = 0;
|
||||
var obj = {
|
||||
a: i++,
|
||||
b: i++,
|
||||
c: i++
|
||||
}
|
||||
assertEq("var i = 0; var obj = {
|
||||
a: i++,
|
||||
b: i++,
|
||||
c: i++
|
||||
}; func(obj.a, obj.b, obj.c)", func(obj.a, obj.b, obj.c));
|
||||
|
||||
var i = 0;
|
||||
assertEq("var i = 0; func(i++, [i++, i++].join(';'), i++)", func(i++, [i++, i++].join(";"), i++));
|
||||
|
||||
clearPrevious = true;
|
||||
|
||||
headerCode += '
|
||||
var buf:Array<Int> = [];
|
||||
|
||||
function a() {
|
||||
buf.push(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
function b() {
|
||||
buf.push(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
function c() {
|
||||
buf.push(3);
|
||||
return 3;
|
||||
}
|
||||
|
||||
function d() {
|
||||
buf.push(4);
|
||||
return 4;
|
||||
}
|
||||
|
||||
function e() {
|
||||
buf.push(5);
|
||||
return 5;
|
||||
}
|
||||
|
||||
function f() {
|
||||
buf.push(6);
|
||||
return 6;
|
||||
}
|
||||
|
||||
function begin() {
|
||||
buf = [];
|
||||
return function() {
|
||||
return buf.join("_");
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
var buf:Array<Int> = [];
|
||||
|
||||
function a() {
|
||||
buf.push(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
function b() {
|
||||
buf.push(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
function c() {
|
||||
buf.push(3);
|
||||
return 3;
|
||||
}
|
||||
|
||||
function d() {
|
||||
buf.push(4);
|
||||
return 4;
|
||||
}
|
||||
|
||||
function e() {
|
||||
buf.push(5);
|
||||
return 5;
|
||||
}
|
||||
|
||||
function f() {
|
||||
buf.push(6);
|
||||
return 6;
|
||||
}
|
||||
|
||||
function begin() {
|
||||
buf = [];
|
||||
return function() {
|
||||
return buf.join("_");
|
||||
}
|
||||
}
|
||||
|
||||
// &&
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 0 && (c() + d()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 0 && (c() + d()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 99 && (c() + d()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 99 && (c() + d()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 0 && (c() + d()) >= 0 && (e() + f()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 0 && (c() + d()) >= 0 && (e() + f()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 99 && (c() + d()) >= 0 && (e() + f()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 99 && (c() + d()) >= 0 && (e() + f()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 0 && (c() + d()) >= 99 && (e() + f()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 0 && (c() + d()) >= 99 && (e() + f()) >= 0;
|
||||
end()', end());
|
||||
|
||||
// ||
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 0 || (c() + d()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 0 || (c() + d()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 99 || (c() + d()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 99 || (c() + d()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 0 || (c() + d()) >= 0 || (e() + f()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 0 || (c() + d()) >= 0 || (e() + f()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 99 || (c() + d()) >= 0 || (e() + f()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 99 || (c() + d()) >= 0 || (e() + f()) >= 0;
|
||||
end()', end());
|
||||
|
||||
var end = begin();
|
||||
(a() + b()) >= 99 || (c() + d()) >= 99 || (e() + f()) >= 0;
|
||||
assertEq('var end = begin();
|
||||
(a() + b()) >= 99 || (c() + d()) >= 99 || (e() + f()) >= 0;
|
||||
end()', end());
|
||||
|
||||
headerCode += '
|
||||
function arr(x, y) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function idx(x, y) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function f1() {
|
||||
buf.push(1);
|
||||
return function(i) { };
|
||||
}
|
||||
|
||||
function f2() {
|
||||
buf.push(2);
|
||||
return 2;
|
||||
}
|
||||
';
|
||||
// []
|
||||
|
||||
function arr(x, y) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function idx(x, y) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function f1() {
|
||||
buf.push(1);
|
||||
return function(i) { };
|
||||
}
|
||||
|
||||
function f2() {
|
||||
buf.push(2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
var end = begin();
|
||||
var _ = (arr(a(), b()))[idx(c(), d())];
|
||||
assertEq('var end = begin();
|
||||
var _ = (arr(a(), b()))[idx(c(), d())];
|
||||
end()', end());
|
||||
|
||||
headerCode += '
|
||||
var d:Dynamic = { f1: f1 };
|
||||
|
||||
function f3() {
|
||||
buf.push(3);
|
||||
d.f1 = function f3df1(i) {
|
||||
buf.push(4);
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
';
|
||||
|
||||
var d:Dynamic = { f1: f1 };
|
||||
|
||||
function f3() {
|
||||
buf.push(3);
|
||||
d.f1 = function(i) {
|
||||
buf.push(4);
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
Util.runKnownBug("Function arguments get called first, before function is evaluated", () ->{
|
||||
var end = begin();
|
||||
d.f1()(f3());
|
||||
d.f1(f2());
|
||||
assertEq('var end = begin();
|
||||
// Expected internal behavior for `d.f1()(f3());`
|
||||
//var func = d.f1();
|
||||
//func(f3());
|
||||
|
||||
d.f1()(f3());
|
||||
d.f1(f2());
|
||||
end()', end());
|
||||
});
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class FinalCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
Util.defaultImport = false;
|
||||
var interp = super.getNewInterp();
|
||||
Util.defaultImport = true;
|
||||
//interp.variables.set("Std", Std);
|
||||
//interp.variables.set("String", String);
|
||||
//interp.variables.set("Bool", Bool);
|
||||
//interp.variables.set("Float", Float);
|
||||
//interp.variables.set("Array", Array);
|
||||
//interp.variables.set("Int", Int);
|
||||
//interp.variables.set("IntIterator", IntIterator);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
headerCode = "var i = 5; var x = 10;";
|
||||
|
||||
var i = 5; var x = 10;
|
||||
|
||||
assertDisplay("(i - x) * 30 + 90", ((i-x) * 30) + 90);
|
||||
assertDisplay("i - x * 30 + 90", i-x * 30 + 90);
|
||||
|
||||
/*
|
||||
// Test operator precedence
|
||||
assertDisplay("i / x * 30 + 90", i / x * 30 + 90);
|
||||
assertDisplay("i / (x * 30) + 90", i / (x * 30) + 90);
|
||||
|
||||
assertDisplay("x * 30 / i + 90", x * 30 / i + 90);
|
||||
//assertEq("(x * 30) / i + 90", x * 30 / i + 90);
|
||||
|
||||
// (_) -> {a = false;}
|
||||
// Shouldnt be converted to (_) -> return {a = false;}
|
||||
|
||||
Util.parse("openCodesList(false, codesOpened ? false : true, previousOpen != open ? true : false);");
|
||||
Util.parse("openCodesList(false, 'HELLO' ? false : false, 'WORLD' ? true : true);");
|
||||
Util.parse('FlxTween.tween(newSprite, {"scale.x": 1, "scale.y": 1, alpha: 1, angle: 0}, 0.3, {ease: FlxEase.qaudInOut});');
|
||||
Util.parse('
|
||||
bloomShader.dim = dim = .8 + (.3 * FlxMath.fastSin(__totalTime));
|
||||
bloomShader.size = size = 18 + (8 * FlxMath.fastSin(__totalTime));
|
||||
');
|
||||
*/
|
||||
|
||||
Util.parse('sprite.setPosition(codesList.x + (sprite.ID % 2 == 1 ? 240 : 67),codesList.y + (15 * sprite.ID) + (sprite.ID%2 == 1 ? 35 : 54));');
|
||||
|
||||
headerCode = "import tests.FinalCase.TestEnum;";
|
||||
|
||||
assertEq("TestEnum.A", TestEnum.A);
|
||||
assertEq("TestEnum.B", TestEnum.B);
|
||||
assertEq("TestEnum.C(1, 2)", TestEnum.C(1, 2));
|
||||
assertEq("TestEnum.D(1, 2, 3)", TestEnum.D(1, 2, 3));
|
||||
|
||||
Util.parse('test ? 0xFF343434 : 0xFF92A2FF');
|
||||
Util.parse('test ? 1 : 0.75;');
|
||||
|
||||
Util.runKnownBug("Function then array causes error, unless the function ends with ;", function() {
|
||||
headerCode = "";
|
||||
function isEven(i:Int):Bool { return i % 2 == 0; }
|
||||
assertEq("function isEven(i:Int):Bool { return i % 2 == 0; }[for(i in 0...10) if(i % 2 == 0) i => isEven(i) else i => isEven(i)]", [for(i in 0...10) if(i % 2 == 0) i => isEven(i) else i => isEven(i)]);
|
||||
});
|
||||
|
||||
assertEq("[for(i in 0...10) i]", [for(i in 0...10) i]);
|
||||
assertEq("[for(i in 0...10) i => null]", [for(i in 0...10) i => null]);
|
||||
assertEq("[for(i in 0...10) if(i % 2 == 0) i => 'even' else i => 'odd']", [for(i in 0...10) if(i % 2 == 0) i => 'even' else i => 'odd']);
|
||||
assertEq("[for(i in 0...10) if(i % 2 == 0) 'even' else 'odd']", [for(i in 0...10) if(i % 2 == 0) 'even' else 'odd']);
|
||||
assertEq("[for(i in 0...10) for(j in 0...10) i * j]", [for(i in 0...10) for(j in 0...10) i * j]);
|
||||
|
||||
headerCode = "function isEven(i:Int):Bool { return i % 2 == 0; };";
|
||||
function isEven(i:Int):Bool { return i % 2 == 0; }
|
||||
|
||||
assertEq("[for(i in 0...10) if(i % 2 == 0) i => isEven(i) else i => isEven(i)]", [for(i in 0...10) if(i % 2 == 0) i => isEven(i) else i => isEven(i)]);
|
||||
assertEq("[for(i in 0...10) if(i % 2 == 0) isEven(i) else isEven(i)]", [for(i in 0...10) if(i % 2 == 0) isEven(i) else isEven(i)]);
|
||||
headerCode = "function area(a:Int, b:Int):Int { return a * b; };";
|
||||
function area(a:Int, b:Int):Int { return a * b; }
|
||||
|
||||
assertEq("[for(i in 0...10) for(j in 0...10) area(i, j)]", [for(i in 0...10) for(j in 0...10) area(i, j)]);
|
||||
|
||||
|
||||
headerCode = "";
|
||||
|
||||
assertEq("[0=>'hello', 1=>'world']", [0=>'hello', 1=>'world']);
|
||||
assertEq("[0=>'hello', 1=>'world'][1]", [0=>'hello', 1=>'world'][1]);
|
||||
assertEq("[0=>'hello', 5=>'world'][1]", [0=>'hello', 5=>'world'][1]);
|
||||
|
||||
assertEq("
|
||||
import tests.FinalCase;
|
||||
|
||||
FinalCase.test1();
|
||||
", FinalCase.test1());
|
||||
|
||||
assertEq("
|
||||
import tests.FinalCase as FC;
|
||||
|
||||
FC.test1();
|
||||
", FinalCase.test1());
|
||||
|
||||
assertEq("
|
||||
import tests.FinalCase as FC;
|
||||
import tests.FinalCase.test;
|
||||
|
||||
FC.test1() + test();
|
||||
", FinalCase.test1() + test());
|
||||
|
||||
assertEq("
|
||||
//import Std.isOfType;
|
||||
|
||||
Std.isOfType('', String);
|
||||
", Std.isOfType('', String));
|
||||
|
||||
assertEq("
|
||||
import Std.isOfType;
|
||||
|
||||
isOfType('', String);
|
||||
", Std.isOfType('', String));
|
||||
|
||||
assertEq("
|
||||
import Math.round as F;
|
||||
F(2.9);", Math.round(2.9));
|
||||
|
||||
assertEq("
|
||||
import Math.round;
|
||||
round(1.9);", Math.round(1.9));
|
||||
|
||||
// Test EOF with preprocessor
|
||||
}
|
||||
|
||||
static function test1() {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
static function test() {
|
||||
return "world";
|
||||
}
|
||||
|
||||
function assertDisplay(script:String, expected:Dynamic) {
|
||||
var _script = script;
|
||||
script = '"${script}";\n' + script;
|
||||
assertEq(script, expected, _script);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
A;
|
||||
B;
|
||||
C(a:Int, b:Int);
|
||||
D(a:Int, b:Int, c:Int);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class FloatCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
|
||||
headerCode = "
|
||||
var nan = Math.NaN;
|
||||
var pinf = Math.POSITIVE_INFINITY;
|
||||
var ninf = Math.NEGATIVE_INFINITY;
|
||||
var fl:Float = 0.0;
|
||||
";
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var nan = Math.NaN;
|
||||
var pinf = Math.POSITIVE_INFINITY;
|
||||
var ninf = Math.NEGATIVE_INFINITY;
|
||||
var fl:Float = 0.0;
|
||||
|
||||
assertEq("fl > nan", fl > nan);
|
||||
assertEq("fl < nan", fl < nan);
|
||||
assertEq("fl >= nan", fl >= nan);
|
||||
assertEq("fl <= nan", fl <= nan);
|
||||
assertEq("fl == nan", fl == nan);
|
||||
assertEq("fl != nan", fl != nan);
|
||||
|
||||
assertEq("nan > nan", nan > nan);
|
||||
assertEq("nan < nan", nan < nan);
|
||||
assertEq("nan >= nan", nan >= nan);
|
||||
assertEq("nan <= nan", nan <= nan);
|
||||
assertEq("nan == nan", nan == nan);
|
||||
assertEq("nan != nan", nan != nan);
|
||||
|
||||
assertEq("pinf > nan", pinf > nan);
|
||||
assertEq("pinf < nan", pinf < nan);
|
||||
assertEq("pinf >= nan", pinf >= nan);
|
||||
assertEq("pinf <= nan", pinf <= nan);
|
||||
assertEq("pinf == nan", pinf == nan);
|
||||
assertEq("pinf != nan", pinf != nan);
|
||||
|
||||
assertEq("ninf > nan", ninf > nan);
|
||||
assertEq("ninf < nan", ninf < nan);
|
||||
assertEq("ninf >= nan", ninf >= nan);
|
||||
assertEq("ninf <= nan", ninf <= nan);
|
||||
assertEq("ninf == nan", ninf == nan);
|
||||
assertEq("ninf != nan", ninf != nan);
|
||||
|
||||
assertEq("nan > fl", nan > fl);
|
||||
assertEq("nan < fl", nan < fl);
|
||||
assertEq("nan >= fl", nan >= fl);
|
||||
assertEq("nan <= fl", nan <= fl);
|
||||
assertEq("nan == fl", nan == fl);
|
||||
assertEq("nan != fl", nan != fl);
|
||||
|
||||
assertEq("nan > pinf", nan > pinf);
|
||||
assertEq("nan < pinf", nan < pinf);
|
||||
assertEq("nan >= pinf", nan >= pinf);
|
||||
assertEq("nan <= pinf", nan <= pinf);
|
||||
assertEq("nan == pinf", nan == pinf);
|
||||
assertEq("nan != pinf", nan != pinf);
|
||||
|
||||
assertEq("nan > ninf", nan > ninf);
|
||||
assertEq("nan < ninf", nan < ninf);
|
||||
assertEq("nan >= ninf", nan >= ninf);
|
||||
assertEq("nan <= ninf", nan <= ninf);
|
||||
assertEq("nan == ninf", nan == ninf);
|
||||
assertEq("nan != ninf", nan != ninf);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class IntIteratorCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("assertEq", Util.assertEq);
|
||||
interp.variables.set("IntIterator", IntIterator);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var ii = new IntIterator(0, 2);
|
||||
var line = 19;
|
||||
execute('
|
||||
var ii = new IntIterator(0, 2);
|
||||
assertEq(ii.hasNext(), ${ii.hasNext()}, "l${line++}");
|
||||
assertEq(ii.next(), ${ii.next()}, "l${line++}");
|
||||
assertEq(ii.hasNext(), ${ii.hasNext()}, "l${line++}");
|
||||
assertEq(ii.next(), ${ii.next()}, "l${line++}");
|
||||
assertEq(ii.hasNext(), ${ii.hasNext()}, "l${line++}");
|
||||
');
|
||||
|
||||
var ii = new IntIterator(0, 2);
|
||||
var r = [];
|
||||
for (i in ii)
|
||||
r.push(i);
|
||||
assertEq('
|
||||
var ii = new IntIterator(0, 2);
|
||||
var r = [];
|
||||
for (i in ii)
|
||||
r.push(i);
|
||||
r
|
||||
', r);
|
||||
|
||||
var ii = new IntIterator(0, 2);
|
||||
var r = [];
|
||||
for (i in ii)
|
||||
r.push(i);
|
||||
for (i in ii)
|
||||
r.push(i);
|
||||
assertEq('
|
||||
var ii = new IntIterator(0, 2);
|
||||
var r = [];
|
||||
for (i in ii)
|
||||
r.push(i);
|
||||
for (i in ii)
|
||||
r.push(i);
|
||||
r
|
||||
', r);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class LambdaCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Lambda", Lambda);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
// has
|
||||
assertEq("Lambda.has([1,2,3],1)", Lambda.has([1,2,3],1));
|
||||
assertEq("Lambda.has([1,2,3],4)", Lambda.has([1,2,3],4));
|
||||
assertEq("Lambda.has([],null)", Lambda.has([],null));
|
||||
assertEq("Lambda.has([null],null)", Lambda.has([null],null));
|
||||
|
||||
// exists
|
||||
assertEq("Lambda.exists([1, 2, 3], function(i) return i == 2)", Lambda.exists([1, 2, 3], function(i) return i == 2));
|
||||
assertEq("Lambda.exists([1, 2, 3], function(i) return i == 4)", Lambda.exists([1, 2, 3], function(i) return i == 4));
|
||||
assertEq("Lambda.exists([], function(x) return true)", Lambda.exists([], function(x) return true));
|
||||
|
||||
// foreach
|
||||
assertEq("Lambda.foreach([2, 4, 6],function(i) return i % 2 == 0)", Lambda.foreach([2, 4, 6],function(i) return i % 2 == 0));
|
||||
assertEq("Lambda.foreach([2, 4, 7],function(i) return i % 2 == 0)", Lambda.foreach([2, 4, 7],function(i) return i % 2 == 0));
|
||||
assertEq("Lambda.foreach([], function(x) return false)", Lambda.foreach([], function(x) return false));
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class ListCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("List", List);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var l4 = new List();
|
||||
l4.add(1);
|
||||
l4.add(2);
|
||||
l4.add(3);
|
||||
l4.add(5);
|
||||
l4.add(8);
|
||||
|
||||
headerCode = "var l4 = new List();
|
||||
l4.add(1);
|
||||
l4.add(2);
|
||||
l4.add(3);
|
||||
l4.add(5);
|
||||
l4.add(8);";
|
||||
|
||||
assertEq("[for (k=>v in l4) k]", [for (k=>v in l4) k]);
|
||||
assertEq("[for (k=>v in l4) v]", [for (k=>v in l4) v]);
|
||||
assertEq("[for (k=>v in l4) k*v]", [for (k=>v in l4) k*v]);
|
||||
|
||||
assertEq("[for (v in l4) v]", [for (v in l4) v]);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class MapCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("IntMap", haxe.ds.IntMap);
|
||||
interp.variables.set("ObjectMap", haxe.ds.ObjectMap);
|
||||
interp.variables.set("StringMap", haxe.ds.StringMap);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
Sys.println("TODO: Write tests for Map");
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class MathCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function run() {
|
||||
assertEq("Math.PI", Math.PI);
|
||||
assertEq("1 + 2", 3);
|
||||
assertEq("1 + 2 + 3", 6);
|
||||
assertEq("1 + 2 + 3 + 4", 10);
|
||||
assertEq("(1 + 2) + 3", 6);
|
||||
assertEq("(1 + 2) + 3 + 4", 10);
|
||||
assertEq("(1 + 2) * 3", 9);
|
||||
assertEq("(1 + 2) * 3 * 4", 36);
|
||||
assertEq("((1 + 2) * 3 * 4) / 2", 18);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class MiscCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Std", Std);
|
||||
interp.variables.set("String", String);
|
||||
interp.variables.set("Bool", Bool);
|
||||
interp.variables.set("Float", Float);
|
||||
interp.variables.set("Array", Array);
|
||||
interp.variables.set("Int", Int);
|
||||
interp.variables.set("IntIterator", IntIterator);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
assertEq("", null);
|
||||
assertEq("true", true);
|
||||
assertEq("false", false);
|
||||
assertEq("null", null);
|
||||
|
||||
Util.runKnownBug("Redefining a variable with the same name as a function", () ->{
|
||||
// Redefining a function with the same name as a variable
|
||||
var a = 1; function a() { return 4; }
|
||||
assertEq("var a = 1; function a() { return 4; }; a", a);
|
||||
});
|
||||
|
||||
var a = 1; var a = 2;
|
||||
assertEq("var a = 1; var a = 2; a", a);
|
||||
|
||||
|
||||
|
||||
assertEq("0",0);
|
||||
assertEq("0xFF", 255);
|
||||
assertEq("0xFF_FF", 0xFFFF);
|
||||
assertEq("0b101", 5); //assertEq("0b101", 0b101);
|
||||
#if !(php || python)
|
||||
#if haxe3
|
||||
assertEq("0xBFFFFFFF", 0xBFFFFFFF);
|
||||
assertEq("0x7FFFFFFF", 0x7FFFFFFF);
|
||||
#elseif !neko
|
||||
assertEq("n(0xBFFFFFFF)", 0xBFFFFFFF, { n : haxe.Int32.toNativeInt });
|
||||
assertEq("n(0x7FFFFFFF)", 0x7FFFFFFF, { n : haxe.Int32.toNativeInt } );
|
||||
#end
|
||||
#end
|
||||
assertEq("-123",-123);
|
||||
assertEq("- 123",-123);
|
||||
assertEq("1.546",1.546);
|
||||
assertEq(".545",.545);
|
||||
assertEq("'bla'","bla");
|
||||
assertEq("null",null);
|
||||
assertEq("true",true);
|
||||
assertEq("false",false);
|
||||
assertEq("1 == 2",false);
|
||||
assertEq("1.3 == 1.3",true);
|
||||
assertEq("5 > 3",true);
|
||||
assertEq("0 < 0",false);
|
||||
assertEq("-1 <= -1",true);
|
||||
assertEq("1 + 2",3);
|
||||
assertEq("~545",-546);
|
||||
assertEq("'abc' + 55","abc55");
|
||||
assertEq("'abc' + 'de'","abcde");
|
||||
assertEq("-1 + 2",1);
|
||||
assertEq("1 / 5",0.2);
|
||||
assertEq("3 * 2 + 5",11);
|
||||
assertEq("3 * (2 + 5)",21);
|
||||
assertEq("3 * 2 // + 5 \n + 6",12);
|
||||
assertEq("3 /* 2\n */ + 5",8);
|
||||
assertEq("[55,66,77][1]",66);
|
||||
assertEq("var a = [55]; a[0] *= 2; a[0]",110);
|
||||
assertEq("x",55,{ x : 55 });
|
||||
assertEq("var y = 33; y",33);
|
||||
assertEq("{ 1; 2; 3; }",3);
|
||||
assertEq("o.val",55,{ o : { val : 55 } });
|
||||
assertEq("o.val",null,{ o : {} });
|
||||
assertEq("var a = 1; a++",1);
|
||||
assertEq("var a = 1; a++; a",2);
|
||||
assertEq("var a = 1; ++a",2);
|
||||
assertEq("var a = 1; a *= 3",3);
|
||||
assertEq("a = b = 3; a + b",6);
|
||||
assertEq("add(1,2)",3,{ add : function(x,y) return x + y });
|
||||
assertEq("a.push(5); a.pop() + a.pop()",{var a = [3]; a.push(5); a.pop() + a.pop();},{ a : [3] });
|
||||
assertEq("if( true ) 1 else 2",1);
|
||||
assertEq("if( false ) 1 else 2",2);
|
||||
assertEq("var t = 0; for( x in [1,2,3] ) t += x; t",6);
|
||||
assertEq("var a = new Array(); for( x in 0...5 ) a[x] = x; a.join('-')","0-1-2-3-4");
|
||||
assertEq("(function(a,b) return a + b)(4,5)",9);
|
||||
assertEq("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10);
|
||||
assertEq("var a = false; do { a = true; } while (!a); a;",true);
|
||||
assertEq("var t = 0; for( x in 1...10 ) t += x; t", 45);
|
||||
#if haxe3
|
||||
assertEq("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45);
|
||||
#else
|
||||
assertEq("var t = 0; for( x in new IntIter(1,10) ) t +=x; t", 45);
|
||||
#end
|
||||
assertEq("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",{var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x;});
|
||||
assertEq("var i=2; if( true ) --i; i",1);
|
||||
assertEq("var i=0; if( i++ > 0 ) i=3; i",1);
|
||||
assertEq("var a = 5/2; a",2.5);
|
||||
assertEq("{ x = 3; x; }", 3);
|
||||
assertEq("{ x : 3, y : {} }.x", 3);
|
||||
assertEq("function bug(){ \n }\nbug().x", null);
|
||||
assertEq("1 + 2 == 3", true);
|
||||
assertEq("-2 == 3 - 5", true);
|
||||
assertEq("var x=-3; x", -3);
|
||||
assertEq("var a:Array<Dynamic>=[1,2,4]; a[2]", 4);
|
||||
assertEq("/**/0", 0);
|
||||
assertEq("x=1;x*=-2", -2);
|
||||
assertEq("var f = x -> x + 1; f(3)", 4);
|
||||
assertEq("var f = () -> 55; f()", 55);
|
||||
assertEq("var f = (x) -> x + 1; f(3)", 4);
|
||||
assertEq("var f = (x:Int) -> x + 1; f(3)", 4);
|
||||
assertEq("var f = (x,y) -> x + y; f(3,1)", 4);
|
||||
assertEq("var f = (x,y:Int) -> x + y; f(3,1)", 4);
|
||||
assertEq("var f = (x:Int,y:Int) -> x + y; f(3,1)", 4);
|
||||
assertEq("var f:Int->Int->Int = (x:Int,y:Int) -> x + y; f(3,1)", {var f:Int->Int->Int = (x:Int,y:Int) -> x + y; f(3,1);});
|
||||
assertEq("var f:(x:Int, y:Int)->Int = (x:Int,y:Int) -> x + y; f(3,1)", {var f:(x:Int, y:Int)->Int = (x:Int,y:Int) -> x + y; f(3,1);});
|
||||
//assertEq("var f:(x:Int)->(y:Int, z:Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", {var f:(x:Int)->(y:Int, z:Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2);});
|
||||
//assertEq("var f:(x:Int)->(Int, Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", {var f:(x:Int)->(Int, Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2);});
|
||||
assertEq("var a = 10; var b = 5; a - -b", 15);
|
||||
assertEq("var a = 10; var b = 5; a - b / 2", 7.5);
|
||||
|
||||
Util.runKnownBug("Redefining a variable in a scope overrides the previous definition", () -> {
|
||||
assertEq("{ var x = 0; } x",55,{ x : 55 });
|
||||
});
|
||||
Util.runKnownBug("Global Y isnt updated from the inside of the function", () -> {
|
||||
assertEq("var y = 0; var add = function(a) y += a; add(5); add(3); y", {var y = 0; var add = function(a) y += a; add(5); add(3); y;});
|
||||
});
|
||||
Util.runKnownBug("Throwing an exception inside a function doesnt return the correct value", () -> {
|
||||
assertEq("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",{
|
||||
var x = 1;
|
||||
var f:Dynamic = function(x) throw x;
|
||||
try
|
||||
f(55)
|
||||
catch( e:Dynamic )
|
||||
e + x;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
assertEq("var a = if( true ) 1 else 2; a",1);
|
||||
assertEq("var a = if( false ) 1 else 2; a",2);
|
||||
assertEq("if(true) 1; null", null);
|
||||
assertEq("if(false) 1; null", null);
|
||||
|
||||
assertEq("[55,66,77][1]",66);
|
||||
|
||||
assertEq("{
|
||||
var a = 1;
|
||||
function b() { return a; }
|
||||
a = 2;
|
||||
b();
|
||||
}", 2);
|
||||
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class ReflectCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Reflect", Reflect);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
headerCode = "var x = { a: 1, b: null };";
|
||||
var x = { a: 1, b: null };
|
||||
|
||||
assertEq("Reflect.field(x, 'a')", Reflect.field(x, 'a'));
|
||||
assertEq("Reflect.field(x, 'b')", Reflect.field(x, 'b'));
|
||||
assertEq("Reflect.field(x, 'c')", Reflect.field(x, 'c'));
|
||||
|
||||
assertEq("Reflect.hasField(x, 'a')", Reflect.hasField(x, 'a'));
|
||||
assertEq("Reflect.hasField(x, 'b')", Reflect.hasField(x, 'b'));
|
||||
assertEq("Reflect.hasField(x, 'c')", Reflect.hasField(x, 'c'));
|
||||
|
||||
headerCode = "var n = null;";
|
||||
var n = null;
|
||||
|
||||
assertEq("Reflect.field(n, n)", Reflect.field(n, n));
|
||||
assertEq("Reflect.field(1, 'foo')", Reflect.field(1, "foo"));
|
||||
|
||||
headerCode = "var x = { a: 1, b: null };";
|
||||
|
||||
Reflect.setField(x, 'a', 2); assertEq("Reflect.setField(x, 'a', 2); x.a", x.a);
|
||||
Reflect.setField(x, 'c', 'foo'); assertEq("Reflect.setField(x, 'c', 'foo'); Reflect.field(x, 'c')", Reflect.field(x, 'c'));
|
||||
|
||||
headerCode = "var x = { a: 1, b: null };";
|
||||
|
||||
Reflect.setProperty(x, 'a', 2); assertEq("Reflect.setProperty(x, 'a', 2); x.a", x.a);
|
||||
Reflect.setProperty(x, 'c', 'foo'); assertEq("Reflect.setProperty(x, 'c', 'foo'); Reflect.field(x, 'c')", Reflect.field(x, 'c'));
|
||||
|
||||
headerCode = "var x = function(t) return 1; var y = function(t) return -1; var z = function(t) return 1;";
|
||||
var x = function(t) return 1;
|
||||
var y = function(t) return -1;
|
||||
var z = function(t) return 1;
|
||||
|
||||
assertEq("Reflect.compareMethods(x,y)", Reflect.compareMethods(x,y));
|
||||
assertEq("Reflect.compareMethods(x,z)", Reflect.compareMethods(x,z));
|
||||
assertEq("Reflect.compareMethods(y,z)", Reflect.compareMethods(y,z));
|
||||
assertEq("Reflect.compareMethods(x,x)", Reflect.compareMethods(x,x));
|
||||
assertEq("Reflect.compareMethods(y,y)", Reflect.compareMethods(y,y));
|
||||
assertEq("Reflect.compareMethods(z,z)", Reflect.compareMethods(z,z));
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class RegexCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
|
||||
/*headerCode = "
|
||||
var r = ~/a/;
|
||||
var rg = ~/a/g;
|
||||
var rg2 = ~/aa/g;
|
||||
";*/
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("assertEq", Util.assertEq);
|
||||
interp.variables.set("EReg", EReg);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var r = new EReg("a", "");
|
||||
var rg = new EReg("a", "g");
|
||||
var rg2 = new EReg("aa", "g");
|
||||
|
||||
// TODO: implement better checking for regexes
|
||||
//assertEq("new EReg('a', '');", r);
|
||||
//assertEq("new EReg('a', 'g');", rg);
|
||||
//assertEq("new EReg('aa', 'g');", rg2);
|
||||
|
||||
//@:privateAccess assertEq("new EReg('a', '').toString();", r.toString());
|
||||
//@:privateAccess assertEq("new EReg('a', 'g').toString();", rg.toString());
|
||||
//@:privateAccess assertEq("new EReg('aa', 'g').toString();", rg2.toString());
|
||||
|
||||
//assertEq(r.match("") == false);
|
||||
//assertEq(r.match("b") == false);
|
||||
//assertEq(r.match("a") == true);
|
||||
//assertEq(r.matched(0) == "a");
|
||||
//assertEq(r.matchedLeft() == "");
|
||||
//assertEq(r.matchedRight() == "");
|
||||
//var pos = r.matchedPos();
|
||||
//assertEq(pos.pos == 0);
|
||||
//assertEq(pos.len == 1);
|
||||
|
||||
headerCode = "var r = ~/a/;";
|
||||
|
||||
assertEq('[r.match(""), r.match("b"), r.match("a"), r.matched(0), r.matchedLeft(), r.matchedRight(), {var pos = r.matchedPos(); [pos.pos, pos.len];}]', [r.match(""), r.match("b"), r.match("a"), r.matched(0), r.matchedLeft(), r.matchedRight(), {var pos = r.matchedPos(); [pos.pos, pos.len];}]);
|
||||
assertEq('[r.match("aa"), r.matched(0), r.match("a"), r.matchedLeft(), r.matchedRight(), {var pos = r.matchedPos(); [pos.pos, pos.len];}]', [r.match("aa"), r.matched(0), r.match("a"), r.matchedLeft(), r.matchedRight(), {var pos = r.matchedPos(); [pos.pos, pos.len];}]);
|
||||
|
||||
|
||||
headerCode = "var rg = ~/a/g;";
|
||||
|
||||
assertEq('[rg.match("aa"), rg.matched(0), rg.matchedLeft(), rg.matchedRight(), {var pos = rg.matchedPos(); [pos.pos, pos.len];}]', [rg.match("aa"), rg.matched(0), rg.matchedLeft(), rg.matchedRight(), {var pos = rg.matchedPos(); [pos.pos, pos.len];}]);
|
||||
|
||||
headerCode = "var rg2 = ~/aa/g;";
|
||||
|
||||
assertEq('[rg2.match("aa"), rg2.matched(0), rg2.matchedLeft(), rg2.matchedRight(), {var pos = rg2.matchedPos(); [pos.pos, pos.len];}]', [rg2.match("aa"), rg2.matched(0), rg2.matchedLeft(), rg2.matchedRight(), {var pos = rg2.matchedPos(); [pos.pos, pos.len];}]);
|
||||
assertEq('[rg2.match("AaaBaaC"), rg2.matched(0), rg2.matchedLeft(), rg2.matchedRight(), {var pos = rg2.matchedPos(); [pos.pos, pos.len];}]', [rg2.match("AaaBaaC"), rg2.matched(0), rg2.matchedLeft(), rg2.matchedRight(), {var pos = rg2.matchedPos(); [pos.pos, pos.len];}]);
|
||||
|
||||
headerCode = "";
|
||||
|
||||
// split
|
||||
assertEq('~/a/.split("")', ~/a/.split(""));
|
||||
assertEq('~/a/.split("a")', ~/a/.split("a"));
|
||||
assertEq('~/a/.split("aa")', ~/a/.split("aa"));
|
||||
assertEq('~/a/.split("b")', ~/a/.split("b"));
|
||||
assertEq('~/a/.split("ab")', ~/a/.split("ab"));
|
||||
assertEq('~/a/.split("ba")', ~/a/.split("ba"));
|
||||
assertEq('~/a/.split("aba")', ~/a/.split("aba"));
|
||||
assertEq('~/a/.split("bab")', ~/a/.split("bab"));
|
||||
assertEq('~/a/.split("baba")', ~/a/.split("baba"));
|
||||
|
||||
// split + g
|
||||
assertEq('~/a/g.split("")', ~/a/g.split(""));
|
||||
assertEq('~/a/g.split("a")', ~/a/g.split("a"));
|
||||
assertEq('~/a/g.split("aa")', ~/a/g.split("aa"));
|
||||
assertEq('~/a/g.split("b")', ~/a/g.split("b"));
|
||||
assertEq('~/a/g.split("ab")', ~/a/g.split("ab"));
|
||||
assertEq('~/a/g.split("ba")', ~/a/g.split("ba"));
|
||||
assertEq('~/a/g.split("aba")', ~/a/g.split("aba"));
|
||||
assertEq('~/a/g.split("bab")', ~/a/g.split("bab"));
|
||||
assertEq('~/a/g.split("baba")', ~/a/g.split("baba"));
|
||||
|
||||
// replace
|
||||
assertEq('~/a/.replace("", "z")', ~/a/.replace("", "z"));
|
||||
assertEq('~/a/.replace("a", "z")', ~/a/.replace("a", "z"));
|
||||
assertEq('~/a/.replace("aa", "z")', ~/a/.replace("aa", "z"));
|
||||
assertEq('~/a/.replace("b", "z")', ~/a/.replace("b", "z"));
|
||||
assertEq('~/a/.replace("ab", "z")', ~/a/.replace("ab", "z"));
|
||||
assertEq('~/a/.replace("ba", "z")', ~/a/.replace("ba", "z"));
|
||||
assertEq('~/a/.replace("aba", "z")', ~/a/.replace("aba", "z"));
|
||||
assertEq('~/a/.replace("bab", "z")', ~/a/.replace("bab", "z"));
|
||||
assertEq('~/a/.replace("baba", "z")', ~/a/.replace("baba", "z"));
|
||||
|
||||
//Util.runKnownBug("Regex Syntax doesn't work", () -> {
|
||||
assertCompiles("~/a/;");
|
||||
assertCompiles("~/(a)a\\0\\//g;");
|
||||
assertCompiles("~/(a)a\\0\\//g+5;");
|
||||
assertError("~/(a)a\\0\\//ga;", Parser.getBaseError(ECustom("Invalid regex expression option \"a\"")));
|
||||
//assertEq("~/a/+5", null);//~/a/+5);
|
||||
//});
|
||||
|
||||
// replace + g
|
||||
assertEq('~/a/g.replace("", "z")', ~/a/g.replace("", "z"));
|
||||
assertEq('~/a/g.replace("a", "z")', ~/a/g.replace("a", "z"));
|
||||
assertEq('~/a/g.replace("aa", "z")', ~/a/g.replace("aa", "z"));
|
||||
assertEq('~/a/g.replace("b", "z")', ~/a/g.replace("b", "z"));
|
||||
assertEq('~/a/g.replace("ab", "z")', ~/a/g.replace("ab", "z"));
|
||||
assertEq('~/a/g.replace("ba", "z")', ~/a/g.replace("ba", "z"));
|
||||
assertEq('~/a/g.replace("aba", "z")', ~/a/g.replace("aba", "z"));
|
||||
assertEq('~/a/g.replace("bab", "z")', ~/a/g.replace("bab", "z"));
|
||||
assertEq('~/a/g.replace("baba", "z")', ~/a/g.replace("baba", "z"));
|
||||
|
||||
// var 0 = 5; // Missing variable identifier
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class StdCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Std", Std);
|
||||
interp.variables.set("String", String);
|
||||
interp.variables.set("Bool", Bool);
|
||||
interp.variables.set("Float", Float);
|
||||
interp.variables.set("Array", Array);
|
||||
interp.variables.set("Int", Int);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var known:String = null; assertEq('var known:String = null; known is String;', known is String);
|
||||
var unknown = null; assertEq('var unknown = null; unknown is String;', unknown is String);
|
||||
assertEq('null is String;', null is String);
|
||||
|
||||
assertEq('"" is String;', ("" is String));
|
||||
assertEq('false is Bool;', (false is Bool));
|
||||
assertEq("1 is Int;", (1 is Int));
|
||||
assertEq("1.5 is Int;", (1.5 is Int));
|
||||
assertEq("1.5 is Float;", (1.5 is Float));
|
||||
assertEq("[] is Array;", ([] is Array));
|
||||
|
||||
// isOfType
|
||||
assertEq("var known:String = null; Std.isOfType(known, String);", Std.isOfType(known, String));
|
||||
|
||||
assertEq("var unknown = null; Std.isOfType(unknown, String);", Std.isOfType(unknown, String));
|
||||
assertEq("Std.isOfType(null, String);", Std.isOfType(null, String));
|
||||
|
||||
assertEq("Std.isOfType('', String);", Std.isOfType("", String));
|
||||
assertEq("Std.isOfType(false, Bool);", Std.isOfType(false, Bool));
|
||||
assertEq("Std.isOfType(1, Int)", Std.isOfType(1, Int));
|
||||
assertEq("Std.isOfType(1.5, Int);", Std.isOfType(1.5, Int));
|
||||
assertEq("Std.isOfType(1.5, Float);", Std.isOfType(1.5, Float));
|
||||
assertEq("Std.isOfType([], Array);", Std.isOfType([], Array));
|
||||
// Std.isOfType(cast unit.MyEnum.A, Array) == false;
|
||||
|
||||
// instance
|
||||
#if !js
|
||||
assertEq("Std.downcast('', String)", Std.downcast("", String));
|
||||
Std.downcast("", String) == "";
|
||||
#end
|
||||
|
||||
var a = [];
|
||||
assertEq("var a = []; Std.downcast(a, Array)", Std.downcast(a, Array));
|
||||
assertEq("Std.downcast(null, Array)", Std.downcast(null, Array));
|
||||
assertEq("Std.downcast(null, String)", Std.downcast(null, String));
|
||||
|
||||
// string
|
||||
/*var cwts = new ClassWithToString();
|
||||
var cwtsc = new ClassWithToStringChild();
|
||||
var cwtsc2 = new ClassWithToStringChild2();
|
||||
|
||||
Std.string(cwts) == "ClassWithToString.toString()";
|
||||
Std.string(cwtsc) == "ClassWithToString.toString()";
|
||||
Std.string(cwtsc2) == "ClassWithToStringChild2.toString()";
|
||||
|
||||
Std.string(SomeEnum.NoArguments) == "NoArguments";
|
||||
Std.string(SomeEnum.OneArgument("foo")) == "OneArgument(foo)";*/
|
||||
|
||||
assertEq("Std.string(null)", Std.string(null));
|
||||
|
||||
// int
|
||||
assertEq("Std.int(-1.7)", Std.int(-1.7));
|
||||
assertEq("Std.int(-1.2)", Std.int(-1.2));
|
||||
assertEq("Std.int(-0.7)", Std.int(-0.7));
|
||||
assertEq("Std.int(-0.2)", Std.int(-0.2));
|
||||
assertEq("Std.int(0.7)", Std.int(0.7));
|
||||
assertEq("Std.int(0.2)", Std.int(0.2));
|
||||
|
||||
// general
|
||||
assertEq("Std.parseInt('0')", Std.parseInt("0"));
|
||||
assertEq("Std.parseInt('-1')", Std.parseInt("-1"));
|
||||
|
||||
// preceeding zeroes
|
||||
assertEq("Std.parseInt('0001')", Std.parseInt("0001"));
|
||||
assertEq("Std.parseInt('0010')", Std.parseInt("0010"));
|
||||
// trailing text
|
||||
assertEq("Std.parseInt('100x123')", Std.parseInt("100x123"));
|
||||
assertEq("Std.parseInt('12foo13')", Std.parseInt("12foo13"));
|
||||
assertEq("Std.parseInt('23e2')", Std.parseInt("23e2"));
|
||||
assertEq("Std.parseInt('0x10z')", Std.parseInt("0x10z"));
|
||||
assertEq("Std.parseInt('0x10x123')", Std.parseInt("0x10x123"));
|
||||
assertEq("Std.parseInt('0x10x123\\n')", Std.parseInt("0x10x123\n"));
|
||||
assertEq("Std.parseInt('0xff\\n')", Std.parseInt("0xff\n"));
|
||||
|
||||
// hexadecimals
|
||||
assertEq("Std.parseInt('0xff')", Std.parseInt("0xff"));
|
||||
assertEq("Std.parseInt('0x123')", Std.parseInt("0x123"));
|
||||
assertEq("Std.parseInt('0XFF')", Std.parseInt("0XFF"));
|
||||
assertEq("Std.parseInt('0X123')", Std.parseInt("0X123"));
|
||||
assertEq("Std.parseInt('0X01')", Std.parseInt("0X01"));
|
||||
assertEq("Std.parseInt('0x01')", Std.parseInt("0x01"));
|
||||
|
||||
// signs
|
||||
assertEq("Std.parseInt('123')", Std.parseInt("123"));
|
||||
assertEq("Std.parseInt('+123')", Std.parseInt("+123"));
|
||||
assertEq("Std.parseInt('-123')", Std.parseInt("-123"));
|
||||
assertEq("Std.parseInt('0xa0')", Std.parseInt("0xa0"));
|
||||
assertEq("Std.parseInt('+0xa0')", Std.parseInt("+0xa0"));
|
||||
assertEq("Std.parseInt('-0xa0')", Std.parseInt("-0xa0"));
|
||||
|
||||
// whitespace: space, horizontal tab, newline, vertical tab, form feed, and carriage return
|
||||
assertEq("Std.parseInt(' 5')", Std.parseInt(" 5"));
|
||||
|
||||
// whitespace and signs
|
||||
assertEq("Std.parseInt(' 16')", Std.parseInt(" 16"));
|
||||
assertEq("Std.parseInt(' -16')", Std.parseInt(" -16"));
|
||||
assertEq("Std.parseInt(' +16')", Std.parseInt(" +16"));
|
||||
assertEq("Std.parseInt(' 0x10')", Std.parseInt(" 0x10"));
|
||||
assertEq("Std.parseInt(' -0x10')", Std.parseInt(" -0x10"));
|
||||
assertEq("Std.parseInt(' +0x10')", Std.parseInt(" +0x10"));
|
||||
|
||||
// binary and octal unsupported
|
||||
assertEq("Std.parseInt('010')", Std.parseInt("010"));
|
||||
assertEq("Std.parseInt('0b10')", Std.parseInt("0b10"));
|
||||
// null
|
||||
assertEq("Std.parseInt(null)", Std.parseInt(null));
|
||||
// no number
|
||||
assertEq("Std.parseInt('')", Std.parseInt(""));
|
||||
assertEq("Std.parseInt('abcd')", Std.parseInt("abcd"));
|
||||
assertEq("Std.parseInt('a10')", Std.parseInt("a10"));
|
||||
// invalid use of signs
|
||||
assertEq("Std.parseInt('++123')", Std.parseInt("++123"));
|
||||
assertEq("Std.parseInt('+-123')", Std.parseInt("+-123"));
|
||||
assertEq("Std.parseInt('-+123')", Std.parseInt("-+123"));
|
||||
assertEq("Std.parseInt('--123')", Std.parseInt("--123"));
|
||||
assertEq("Std.parseInt('+ 123')", Std.parseInt("+ 123"));
|
||||
assertEq("Std.parseInt('- 123')", Std.parseInt("- 123"));
|
||||
assertEq("Std.parseInt('++0x123')", Std.parseInt("++0x123"));
|
||||
assertEq("Std.parseInt('+-0x123')", Std.parseInt("+-0x123"));
|
||||
assertEq("Std.parseInt('-+0x123')", Std.parseInt("-+0x123"));
|
||||
assertEq("Std.parseInt('--0x123')", Std.parseInt("--0x123"));
|
||||
assertEq("Std.parseInt('+ 0x123')", Std.parseInt("+ 0x123"));
|
||||
assertEq("Std.parseInt('- 0x123')", Std.parseInt("- 0x123"));
|
||||
|
||||
// hexadecimal prefix with no number
|
||||
//unspec(Std.parseInt.bind("0x"));
|
||||
//unspec(Std.parseInt.bind("0x C"));
|
||||
//unspec(Std.parseInt.bind("0x+A"));
|
||||
|
||||
// parseFloat
|
||||
|
||||
// general
|
||||
assertEq("Std.parseFloat('0')", Std.parseFloat('0'));
|
||||
assertEq("Std.parseFloat('0.0')", Std.parseFloat('0.0'));
|
||||
// preceeding zeroes
|
||||
assertEq("Std.parseFloat('0001')", Std.parseFloat('0001'));
|
||||
assertEq("Std.parseFloat('0010')", Std.parseFloat('0010'));
|
||||
// trailing text
|
||||
assertEq("Std.parseFloat('100x123')", Std.parseFloat('100x123'));
|
||||
assertEq("Std.parseFloat('12foo13')", Std.parseFloat('12foo13'));
|
||||
assertEq("Std.parseFloat('5.3 ')", Std.parseFloat('5.3 '));
|
||||
assertEq("Std.parseFloat('5.3 1')", Std.parseFloat('5.3 1'));
|
||||
// signs
|
||||
assertEq("Std.parseFloat('123.45')", Std.parseFloat('123.45'));
|
||||
assertEq("Std.parseFloat('+123.45')", Std.parseFloat('+123.45'));
|
||||
// whitespace: space, horizontal tab, newline, vertical tab, form feed, and carriage return
|
||||
// whitespace and signs
|
||||
assertEq("Std.parseFloat(' 1.6')", Std.parseFloat(' 1.6'));
|
||||
assertEq("Std.parseFloat(' -1.6')", Std.parseFloat(' -1.6'));
|
||||
assertEq("Std.parseFloat(' +1.6')", Std.parseFloat(' +1.6'));
|
||||
// exponent
|
||||
assertEq("Std.parseFloat('2.426670815e12')", Std.parseFloat('2.426670815e12'));
|
||||
assertEq("Std.parseFloat('2.426670815E12')", Std.parseFloat('2.426670815E12'));
|
||||
assertEq("Std.parseFloat('2.426670815e+12')", Std.parseFloat('2.426670815e+12'));
|
||||
assertEq("Std.parseFloat('2.426670815E+12')", Std.parseFloat('2.426670815E+12'));
|
||||
assertEq("Std.parseFloat('2.426670815e-12')", Std.parseFloat('2.426670815e-12'));
|
||||
assertEq("Std.parseFloat('2.426670815E-12')", Std.parseFloat('2.426670815E-12'));
|
||||
|
||||
#if !interp
|
||||
assertEq("Std.parseFloat('6e')", Std.parseFloat('6e'));
|
||||
assertEq("Std.parseFloat('6e')", Std.parseFloat('6e'));
|
||||
#end
|
||||
// null
|
||||
assertEq("Math.isNaN(Std.parseFloat(null))", Math.isNaN(Std.parseFloat(null)));
|
||||
// no number
|
||||
assertEq("Math.isNaN(Std.parseFloat(''))", Math.isNaN(Std.parseFloat("")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('abcd'))", Math.isNaN(Std.parseFloat("abcd")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('a10'))", Math.isNaN(Std.parseFloat("a10")));
|
||||
// invalid use of signs
|
||||
assertEq("Math.isNaN(Std.parseFloat('++12.3'))", Math.isNaN(Std.parseFloat("++12.3")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('+-12.3'))", Math.isNaN(Std.parseFloat("+-12.3")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('-+12.3'))", Math.isNaN(Std.parseFloat("-+12.3")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('--12.3'))", Math.isNaN(Std.parseFloat("--12.3")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('+ 12.3'))", Math.isNaN(Std.parseFloat("+ 12.3")));
|
||||
assertEq("Math.isNaN(Std.parseFloat('- 12.3'))", Math.isNaN(Std.parseFloat("- 12.3")));
|
||||
|
||||
// random
|
||||
// var x = Std.random(2);
|
||||
// //x in [0,1];
|
||||
// Std.random(1) == 0;
|
||||
// Std.random(0) == 0;
|
||||
// Std.random(-100) == 0;
|
||||
|
||||
|
||||
Util.runKnownBug("Not all escape sequences are supported", () -> {
|
||||
assertEq("Std.parseInt(' \\t\\n\\x0b\\x0c\\r16')", Std.parseInt(" \t\n\x0b\x0c\r16"));
|
||||
assertEq("Std.parseInt(' \\t\\n\\x0b\\x0c\\r0xa')", Std.parseInt(" \t\n\x0b\x0c\r0xa"));
|
||||
assertEq("Std.parseFloat(' \\t\\n\\x0b\\x0c\\r1.6')", Std.parseFloat('\t\n\x0b\x0c\r1.6'));
|
||||
});
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class StringBufCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Std", Std);
|
||||
interp.variables.set("StringBuf", StringBuf);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
var x = new StringBuf();
|
||||
x.addSub("abcdefg", 1);
|
||||
assertEq('var x = new StringBuf(); x.addSub("abcdefg", 1); x.toString()', x.toString());
|
||||
|
||||
Util.runKnownBug("Emojis dont work", () -> {
|
||||
var x = new StringBuf();
|
||||
x.add("👽");
|
||||
assertEq('var x = new StringBuf(); x.add("👽"); x.toString()', x.toString());
|
||||
});
|
||||
|
||||
var x = new StringBuf();
|
||||
x.add(0x1F47D);
|
||||
assertEq('var x = new StringBuf(); x.add(0x1F47D); x.toString()', x.toString());
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class StringCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Std", Std);
|
||||
interp.variables.set("String", String);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
assertEq('"foo"', "foo");
|
||||
var str = "foo";
|
||||
assertEq('var str = "foo"; str == new String(str)', str == new String(str));
|
||||
|
||||
assertEq('"foo".toUpperCase()', "foo".toUpperCase());
|
||||
assertEq('"_bar".toUpperCase()', "_bar".toUpperCase());
|
||||
assertEq('"123b".toUpperCase()', "123b".toUpperCase());
|
||||
assertEq('"".toUpperCase()', "".toUpperCase());
|
||||
assertEq('"A".toUpperCase()', "A".toUpperCase());
|
||||
assertEq('"FOO".toLowerCase()', "FOO".toLowerCase());
|
||||
assertEq('"_BAR".toLowerCase()', "_BAR".toLowerCase());
|
||||
assertEq('"_BAR".toLowerCase()', "_BAR".toLowerCase());
|
||||
assertEq('"123B".toLowerCase()', "123B".toLowerCase());
|
||||
assertEq('"".toLowerCase()', "".toLowerCase());
|
||||
assertEq('"a".toLowerCase()', "a".toLowerCase());
|
||||
|
||||
headerCode = 'var s = "foo1bar";';
|
||||
var s = "foo1bar";
|
||||
|
||||
assertEq("s.charAt(0)", s.charAt(0));
|
||||
assertEq("s.charAt(1)", s.charAt(1));
|
||||
assertEq("s.charAt(2)", s.charAt(2));
|
||||
assertEq("s.charAt(3)", s.charAt(3));
|
||||
assertEq("s.charAt(4)", s.charAt(4));
|
||||
assertEq("s.charAt(5)", s.charAt(5));
|
||||
assertEq("s.charAt(6)", s.charAt(6));
|
||||
assertEq("s.charAt(7)", s.charAt(7));
|
||||
assertEq("s.charAt(-1)", s.charAt(-1));
|
||||
assertEq('"".charAt(0)', "".charAt(0));
|
||||
assertEq('"".charAt(1)', "".charAt(1));
|
||||
assertEq('"".charAt(-1)', "".charAt(-1));
|
||||
|
||||
headerCode = 'var s = "foo1bar";';
|
||||
var s = "foo1bar";
|
||||
|
||||
assertEq("s.charCodeAt(0)", s.charCodeAt(0));
|
||||
assertEq("s.charCodeAt(1)", s.charCodeAt(1));
|
||||
assertEq("s.charCodeAt(2)", s.charCodeAt(2));
|
||||
assertEq("s.charCodeAt(3)", s.charCodeAt(3));
|
||||
assertEq("s.charCodeAt(4)", s.charCodeAt(4));
|
||||
assertEq("s.charCodeAt(5)", s.charCodeAt(5));
|
||||
assertEq("s.charCodeAt(6)", s.charCodeAt(6));
|
||||
assertEq("s.charCodeAt(7)", s.charCodeAt(7));
|
||||
assertEq("s.charCodeAt(-1)", s.charCodeAt(-1));
|
||||
|
||||
headerCode = '';
|
||||
|
||||
assertEq('("3" > "11")', ("3" > "11"));
|
||||
assertEq('(" 3" < "3")', (" 3" < "3"));
|
||||
assertEq('("a" < "b")', ("a" < "b"));
|
||||
assertEq('("a" <= "b")', ("a" <= "b"));
|
||||
assertEq('("a" > "b")', ("a" > "b"));
|
||||
assertEq('("a" >= "b")', ("a" >= "b"));
|
||||
|
||||
assertEq('"foo".toUpperCase()', "foo".toUpperCase());
|
||||
assertEq('"_bar".toUpperCase()', "_bar".toUpperCase());
|
||||
assertEq('"123b".toUpperCase()', "123b".toUpperCase());
|
||||
assertEq('"".toUpperCase()', "".toUpperCase());
|
||||
assertEq('"A".toUpperCase()', "A".toUpperCase());
|
||||
assertEq('"FOO".toLowerCase()', "FOO".toLowerCase());
|
||||
assertEq('"_BAR".toLowerCase()', "_BAR".toLowerCase());
|
||||
assertEq('"_BAR".toLowerCase()', "_BAR".toLowerCase());
|
||||
assertEq('"123B".toLowerCase()', "123B".toLowerCase());
|
||||
assertEq('"".toLowerCase()', "".toLowerCase());
|
||||
assertEq('"a".toLowerCase()', "a".toLowerCase());
|
||||
|
||||
assertEqPrintable("' \\t\\n\\x0b\\x0c\\r16'", " \t\n\x0b\x0c\r16");
|
||||
assertEqPrintable("' \\t\\n\\x0b\\x0c\\r0xa'", " \t\n\x0b\x0c\r0xa");
|
||||
assertEqPrintable("' \\t\\n\\x0b\\x0c\\r1.6'", ' \t\n\x0b\x0c\r1.6');
|
||||
|
||||
assertEqPrintable("'The \\x54\\141b\\tch\\141r\\141ct\\145r:\\n'", 'The \x54\141b\tch\141r\141ct\145r:\n');
|
||||
assertEqPrintable("'\\t\\\"\\101scii\\\"\\n'", '\t\"\101scii\"\n');
|
||||
assertEqPrintable("'\\tcontains\\n'", '\tcontains\n');
|
||||
assertEqPrintable("'\\tspecial\\\\backslash\\\\codes,\\n'", '\tspecial\\backslash\\codes,\n');
|
||||
assertEqPrintable("'\\tdouble quotes \\\"like this\\\",\\n'", '\tdouble quotes \"like this\",\n');
|
||||
assertEqPrintable("'\\tsingle quotes \\'and this\\',\\n'", '\tsingle quotes \'and this\',\n');
|
||||
assertEqPrintable("'\\tASCII bell\\x07and others.\\n'", '\tASCII bell\x07and others.\n');
|
||||
assertEqPrintable("'Unicode samples: Greek \\u03B1 (alpha), smiley \\u263A,\\n'", 'Unicode samples: Greek \u03B1 (alpha), smiley \u263A,\n');
|
||||
assertEqPrintable("'regional indicators \\u{1F1FA}\\u{1F1F8}, and musical note \\u{1F3B5}.'", 'regional indicators \u{1F1FA}\u{1F1F8}, and musical note \u{1F3B5}.');
|
||||
assertEqPrintable("'\\u{10FFFF}\\u{1F1FA}\\u{3042}\\u{3B1}\\u{F1}\\u{A}'", '\u{10FFFF}\u{1F1FA}\u{3042}\u{3B1}\u{F1}\u{A}');
|
||||
|
||||
//trace(hscript.Printer.getEscapedString("\u{10FFFF}\u{1F1FA}\u{3042}\u{3B1}\u{F1}\u{A}"));
|
||||
|
||||
assertEq('"\\""', "\"");
|
||||
assertEq("'\\''", '\'');
|
||||
assertEq("'\\\\'", '\\');
|
||||
assertEq("'\\n'", '\n');
|
||||
assertEq("'\\r'", '\r');
|
||||
assertEq("'\\t'", '\t');
|
||||
assertEq("'\\101'", '\101');
|
||||
assertEq("'/'", '/');
|
||||
|
||||
assertEq('"$${5}"', "${5}");
|
||||
assertEq('"$${5},$${({})}"', "${5},${({})}");
|
||||
assertEq('"$${5},$${\\"Hello\\"}"', "${5},${\"Hello\"}");
|
||||
assertEq('"$${5},$${\'Hello\'}"', "${5},${'Hello'}");
|
||||
assertEq("'$${({})}'", '$${({})}');
|
||||
|
||||
assertEq("'${5},${({})}'", '${5},${({})}');
|
||||
assertEq("'${5},${\"Hello\"}'", '${5},${"Hello"}');
|
||||
assertEq("'${5},${'Hello'}'", '${5},${'Hello'}');
|
||||
assertEq("'$${5}'", '$${5}');
|
||||
assertEq("'${5}'", '${5}');
|
||||
assertEq("'${'${6}world'}'", '${'${6}world'}');
|
||||
var a = 5;
|
||||
headerCode = 'var a = 5;';
|
||||
assertEq("'$a'", '$a');
|
||||
assertEq("'$$a'", '$$a');
|
||||
assertEq("'$ '", '$ ');
|
||||
assertEq("'$0'", '$0');
|
||||
assertEq("'$a+5 Hello ${a+5}'", '$a+5 Hello ${a+5}');
|
||||
//assertEq("'$a+5 Hello ${a+5}'", "" + a + "+5 Hello " + a + 5);
|
||||
headerCode = '';
|
||||
|
||||
assertEq("'hello ${5} world'", 'hello ${5} world');
|
||||
assertEq("'hello ${5}'", 'hello ${5}');
|
||||
|
||||
assertEq('"f".code', "f".code);
|
||||
assertEq('"o".code', "o".code);
|
||||
assertEq('"1".code', "1".code);
|
||||
assertEq('"b".code', "b".code);
|
||||
assertEq('"a".code', "a".code);
|
||||
assertEq('"r".code', "r".code);
|
||||
assertEq('"r".code', "r".code);
|
||||
assertError('"foo".code', Parser.getBaseError(EPreset(INVALID_CHAR_CODE_MULTI))); // multiple chars causes error
|
||||
assertError('"bar".code', Parser.getBaseError(EPreset(INVALID_CHAR_CODE_MULTI))); // multiple chars causes error
|
||||
|
||||
headerCode = '';
|
||||
var a = 103;
|
||||
|
||||
assertEq('String.fromCharCode(65)', String.fromCharCode(65));
|
||||
assertEq('String.fromCharCode(97)', String.fromCharCode(97));
|
||||
assertEq('String.fromCharCode(98)', String.fromCharCode(98));
|
||||
assertEq('String.fromCharCode(99)', String.fromCharCode(99));
|
||||
assertEq('String.fromCharCode(100)', String.fromCharCode(100));
|
||||
assertEq('String.fromCharCode(101)', String.fromCharCode(101));
|
||||
assertEq('String.fromCharCode(102)', String.fromCharCode(102));
|
||||
assertEq('String.fromCharCode(103)', String.fromCharCode(103));
|
||||
assertEq('var a = 103; String.fromCharCode(a)', String.fromCharCode(a));
|
||||
|
||||
assertError("'hello ${}'", Parser.getBaseError(EPreset(EMPTY_INTERPOLATION)));
|
||||
|
||||
assertEq('"".charAt(0)', "".charAt(0));
|
||||
assertEq('"".charAt(1)', "".charAt(1));
|
||||
assertEq('"".charAt(-1)', "".charAt(-1));
|
||||
|
||||
headerCode = '';
|
||||
|
||||
assertEq("'foo1bar'.charCodeAt(0)", 'foo1bar'.charCodeAt(0));
|
||||
assertEq("'foo1bar'.charCodeAt(1)", 'foo1bar'.charCodeAt(1));
|
||||
assertEq("'foo1bar'.charCodeAt(2)", 'foo1bar'.charCodeAt(2));
|
||||
assertEq("'foo1bar'.charCodeAt(3)", 'foo1bar'.charCodeAt(3));
|
||||
assertEq("'foo1bar'.charCodeAt(4)", 'foo1bar'.charCodeAt(4));
|
||||
assertEq("'foo1bar'.charCodeAt(5)", 'foo1bar'.charCodeAt(5));
|
||||
assertEq("'foo1bar'.charCodeAt(6)", 'foo1bar'.charCodeAt(6));
|
||||
assertEq("'foo1bar'.charCodeAt(7)", 'foo1bar'.charCodeAt(7));
|
||||
assertEq("'foo1bar'.charCodeAt(-1)", 'foo1bar'.charCodeAt(-1));
|
||||
assertEq("'foo1bar'.length", 'foo1bar'.length);
|
||||
assertEq("'foo1bar'.split('1')", 'foo1bar'.split('1'));
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package tests;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class StringToolsCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function getNewInterp() {
|
||||
var interp = super.getNewInterp();
|
||||
interp.variables.set("Std", Std);
|
||||
interp.variables.set("String", String);
|
||||
return interp;
|
||||
}
|
||||
|
||||
override function run() {
|
||||
Util.runKnownBug("Using StringTools; not working", () -> {
|
||||
});
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package tests;
|
||||
|
||||
class SwitchCase extends TestCase {
|
||||
override function setup() {
|
||||
super.setup();
|
||||
}
|
||||
|
||||
override function run() {
|
||||
assertEq("switch(1) { case 1: 1; case 2: 2; default: -1; }", switch(1) { case 1: 1; case 2: 2; default: -1; });
|
||||
assertEq("switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; }", switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; });
|
||||
assertEq("switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; }", switch(3) { case 1: 1; case 2: 2; case 3: 3; default: -1; });
|
||||
assertEq("switch(6) { case 1: 1; case 2: 2; case 3: 3; default: -1; }", switch(6) { case 1: 1; case 2: 2; case 3: 3; default: -1; });
|
||||
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-enums.html
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-variable-capture.html (including case _)
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-structure.html
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-array.html
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-guards.html
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-tuples.html
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-extractors.html
|
||||
// TODO: detect https://haxe.org/manual/lf-pattern-matching-exhaustiveness.html
|
||||
// TODO: maybe? https://haxe.org/manual/lf-pattern-matching-unused.html
|
||||
// TODO: add https://haxe.org/manual/lf-pattern-matching-single.html
|
||||
|
||||
assertEq("switch(5) { case 1|4: 'error'; case 5: 0; default: -1; }", switch(5) { case 1|4: 'error'; case 5: 0; default: -1; });
|
||||
assertEq("switch(5) { case 1|4: 'error'; default: -1; }", switch(5) { case 1|4: 'error'; default: -1; });
|
||||
assertEq("switch(5) { case 1,4: 'error'; case 5: 0; default: -1; }", switch(5) { case 1,4: 'error'; case 5: 0; default: -1; });
|
||||
|
||||
Util.runKnownBug("Switch statement with multiple cases in parentheses", () -> {
|
||||
assertEq("switch(5) { case (1|4): 'error'; default: -1; }", switch(5) { case (1|4): 'error'; default: -1; });
|
||||
assertEq("switch(6) { case (1|4|(6|7)): 6; default: -1; }", switch(6) { case (1|4|(6|7)): 6; default: -1; });
|
||||
});
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
super.teardown();
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package tests;
|
||||
|
||||
import hscript.Printer;
|
||||
import hscript.Tools;
|
||||
import hscript.Expr.Error;
|
||||
|
||||
@:access(hscript.Interp)
|
||||
@:access(hscript.Parser)
|
||||
class TestCase extends HScriptRunner {
|
||||
public function assertEq(script:String, expected:Dynamic, ?message:String, ?vars:Dynamic, ?pos:haxe.PosInfos) {
|
||||
if(message == null)
|
||||
message = script;
|
||||
var result = if(vars != null)
|
||||
executeWithVars(script, vars);
|
||||
else
|
||||
execute(script);
|
||||
if(!Util.assertEq(result, expected, message, pos)) {
|
||||
Sys.println("> " + Printer.convertExprToString(lastExpr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function assertCompiles(script:String, ?message:String, ?pos:haxe.PosInfos) {
|
||||
if(message == null)
|
||||
message = script;
|
||||
try {
|
||||
var result = Util.parseUnsafe(script);
|
||||
} catch(e:Error) {
|
||||
var e = Printer.getPrintableError(e);
|
||||
Sys.println("# Error trying to compile: " + script);
|
||||
Sys.println("## Error: " + e);
|
||||
return Util.failed();
|
||||
}
|
||||
return Util.passed();
|
||||
}
|
||||
|
||||
public function assertError(script:String, expectedError:Error, ?message:String, ?vars:Dynamic, ?pos:haxe.PosInfos) {
|
||||
var expectedError = Printer.getPrintableError(expectedError);
|
||||
if(message == null)
|
||||
message = script;
|
||||
try {
|
||||
var result = if(vars != null)
|
||||
executeWithVarsUnsafe(script, vars);
|
||||
else
|
||||
executeUnsafe(script);
|
||||
Sys.println("# For script: " + script);
|
||||
Sys.println("## Expected error: " + expectedError);
|
||||
Sys.println("## Got result: " + result);
|
||||
Sys.println("> " + Printer.convertExprToString(lastExpr));
|
||||
return Util.failed();
|
||||
} catch(e:hscript.Error) {
|
||||
var e = Printer.getPrintableError(e);
|
||||
if(Type.enumEq(e, expectedError)) {
|
||||
return Util.passed();
|
||||
} else {
|
||||
Sys.println("# For script: " + script);
|
||||
Sys.println("## Expected error: " + expectedError);
|
||||
Sys.println("## Actual error: " + e);
|
||||
return Util.failed();
|
||||
}
|
||||
}
|
||||
return Util.failed();
|
||||
}
|
||||
|
||||
public function assertEqPrintable(script:String, expected:Dynamic, ?message:String, ?vars:Dynamic, ?pos:haxe.PosInfos) {
|
||||
if(message == null)
|
||||
message = script;
|
||||
var result = if(vars != null)
|
||||
executeWithVars(script, vars);
|
||||
else
|
||||
execute(script);
|
||||
if(!Util.assertEqPrintable(result, expected, message, pos)) {
|
||||
Sys.println("> " + Printer.convertExprToString(lastExpr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function assertNeq(script:String, expected:Dynamic, ?message:String, ?vars:Dynamic, ?pos:haxe.PosInfos) {
|
||||
if(message == null)
|
||||
message = script;
|
||||
var result = if(vars != null)
|
||||
executeWithVars(script, vars);
|
||||
else
|
||||
execute(script);
|
||||
if(!Util.assertNeq(result, expected, message, pos)) {
|
||||
Sys.println("> " + Printer.convertExprToString(lastExpr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
# Generic Haxe stuffs to make the project compile
|
||||
-cp src
|
||||
-cp ../
|
||||
-D analyzer-optimize
|
||||
-main Main
|
||||
|
||||
# Libraries (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
|
||||
# --library hscript-improved
|
||||
# --library hxcpp-debug-server
|
||||
|
||||
# Defines (MAKE SURE TO KEEP THIS IN SYNC WITH ALL BUILD FILES)
|
||||
--define hscriptPos
|
||||
--define HXCPP_CHECK_POINTER
|
||||
--define HXCPP_STACK_LINE
|
||||
--define HXCPP_DEBUG_LINK
|
||||
--dce no
|
||||
|
||||
# File Specific Defines
|
||||
--define windows
|
||||
|
||||
# Copying the assets from source code to bin folder
|
||||
# --cmd Xcopy assets\ bin\cpp\assets\ /E /H /C /I /Y
|
||||
--cpp bin/cpp
|
||||
--cmd cd bin/cpp
|
||||
--cmd Main.exe
|
||||
Reference in New Issue
Block a user