Turned stuffs to classes to reduce reflection
This commit is contained in:
+32
-11
@@ -31,18 +31,26 @@ enum Const {
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
typedef Expr = {
|
||||
var e : ExprDef;
|
||||
var pmin : Int;
|
||||
var pmax : Int;
|
||||
var origin : String;
|
||||
var line : Int;
|
||||
class Expr {
|
||||
public var e : ExprDef;
|
||||
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;
|
||||
}
|
||||
}
|
||||
enum ExprDef {
|
||||
enum ExprDef
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
enum Expr
|
||||
#end
|
||||
{
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool );
|
||||
@@ -75,7 +83,19 @@ enum Expr {
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
|
||||
}
|
||||
|
||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||
//typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||
class Argument {
|
||||
public var name : String;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
|
||||
|
||||
@@ -106,10 +126,11 @@ class Error {
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ErrorDef {
|
||||
enum ErrorDef
|
||||
#else
|
||||
enum Error {
|
||||
enum Error
|
||||
#end
|
||||
{
|
||||
EInvalidChar( c : Int );
|
||||
EUnexpected( s : String );
|
||||
EUnterminatedString;
|
||||
|
||||
@@ -631,8 +631,10 @@ class Interp {
|
||||
return get(field, f);
|
||||
case EBinop(op, e1, e2):
|
||||
var fop = binops.get(op);
|
||||
#if debug
|
||||
if (fop == null)
|
||||
error(EInvalidOp(op));
|
||||
#end
|
||||
return fop(e1, e2);
|
||||
case EUnop(op, prefix, e):
|
||||
switch (op) {
|
||||
|
||||
+23
-21
@@ -269,7 +269,7 @@ class Parser {
|
||||
if( e == null ) return null;
|
||||
if( pmin == null ) pmin = tokenMin;
|
||||
if( pmax == null ) pmax = tokenMax;
|
||||
return { e : e, pmin : pmin, pmax : pmax, origin : origin, line : line };
|
||||
return new Expr(e, pmin, pmax, origin, line);
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
@@ -389,14 +389,14 @@ class Parser {
|
||||
return parseExprNext(mk(ECheckType(e,t),p1,tokenMax));
|
||||
case TComma:
|
||||
switch( expr(e) ) {
|
||||
case EIdent(v): return parseLambda([{ name : v, t : t }], pmin(e));
|
||||
case EIdent(v): return parseLambda([new Argument(v, t)], pmin(e));
|
||||
default:
|
||||
}
|
||||
default:
|
||||
}
|
||||
case TComma:
|
||||
switch( expr(e) ) {
|
||||
case EIdent(v): return parseLambda([{name:v}], pmin(e));
|
||||
case EIdent(v): return parseLambda([new Argument(v)], pmin(e));
|
||||
default:
|
||||
}
|
||||
default:
|
||||
@@ -504,7 +504,7 @@ class Parser {
|
||||
while( true ) {
|
||||
var id = getIdent();
|
||||
var t = maybe(TDoubleDot) ? parseType() : null;
|
||||
args.push({ name : id, t : t });
|
||||
args.push(new Argument(id, t));
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TComma:
|
||||
@@ -569,28 +569,30 @@ class Parser {
|
||||
if( e == null && resumeErrors )
|
||||
return null;
|
||||
return switch( expr(e) ) {
|
||||
case EBinop(bop, e1, e2): mk(EBinop(bop, makeUnop(op, e1), e2), pmin(e1), pmax(e2));
|
||||
case ETernary(e1, e2, e3): mk(ETernary(makeUnop(op, e1), e2, e3), pmin(e1), pmax(e3));
|
||||
default: mk(EUnop(op,true,e),pmin(e),pmax(e));
|
||||
case EBinop(bop, e1, e2): mk(EBinop(bop, makeUnop(op, e1), e2), pmin(e1), pmax(e2));
|
||||
case ETernary(e1, e2, e3): mk(ETernary(makeUnop(op, e1), e2, e3), pmin(e1), pmax(e3));
|
||||
default: mk(EUnop(op,true,e),pmin(e),pmax(e));
|
||||
}
|
||||
}
|
||||
|
||||
function makeBinop( op, e1, e ) {
|
||||
if(!Tools.isValidBinOp(op))
|
||||
error(EInvalidOp(op),pmin(e1),pmax(e1));
|
||||
if( e == null && resumeErrors )
|
||||
return mk(EBinop(op,e1,e),pmin(e1),pmax(e1));
|
||||
return switch( expr(e) ) {
|
||||
case EBinop(op2,e2,e3):
|
||||
if( opPriority.get(op) <= opPriority.get(op2) && !opRightAssoc.exists(op) )
|
||||
mk(EBinop(op2,makeBinop(op,e1,e2),e3),pmin(e1),pmax(e3));
|
||||
else
|
||||
mk(EBinop(op, e1, e), pmin(e1), pmax(e));
|
||||
case ETernary(e2,e3,e4):
|
||||
if( opRightAssoc.exists(op) )
|
||||
case EBinop(op2,e2,e3):
|
||||
if( opPriority.get(op) <= opPriority.get(op2) && !opRightAssoc.exists(op) )
|
||||
mk(EBinop(op2,makeBinop(op,e1,e2),e3),pmin(e1),pmax(e3));
|
||||
else
|
||||
mk(EBinop(op, e1, e), pmin(e1), pmax(e));
|
||||
case ETernary(e2,e3,e4):
|
||||
if( opRightAssoc.exists(op) )
|
||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
||||
else
|
||||
mk(ETernary(makeBinop(op, e1, e2), e3, e4), pmin(e1), pmax(e));
|
||||
default:
|
||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
||||
else
|
||||
mk(ETernary(makeBinop(op, e1, e2), e3, e4), pmin(e1), pmax(e));
|
||||
default:
|
||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,10 +1047,10 @@ class Parser {
|
||||
switch( expr(e1) ) {
|
||||
case EIdent(i), EParent(expr(_) => EIdent(i)):
|
||||
var eret = parseExpr();
|
||||
return mk(EFunction([{ name : i }], mk(EReturn(eret),pmin(eret))), pmin(e1));
|
||||
return mk(EFunction([new Argument(i)], mk(EReturn(eret),pmin(eret))), pmin(e1));
|
||||
case ECheckType(expr(_) => EIdent(i), t):
|
||||
var eret = parseExpr();
|
||||
return mk(EFunction([{ name : i, t : t }], mk(EReturn(eret),pmin(eret))), pmin(e1));
|
||||
return mk(EFunction([new Argument(i, t)], mk(EReturn(eret),pmin(eret))), pmin(e1));
|
||||
default:
|
||||
}
|
||||
unexpected(tk);
|
||||
@@ -1106,7 +1108,7 @@ class Parser {
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
var arg : Argument = { name : name };
|
||||
var arg : Argument = new Argument(name);
|
||||
args.push(arg);
|
||||
if( opt ) arg.opt = true;
|
||||
if( allowTypes ) {
|
||||
|
||||
+11
-2
@@ -103,12 +103,21 @@ class Tools {
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function mk( e : ExprDef, p : Expr ) {
|
||||
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
||||
#if hscriptPos
|
||||
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||
return new Expr(e, p.pmin, p.pmax, p.origin, 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,4 +33,17 @@ class HScriptRunner {
|
||||
else
|
||||
return interp.exprReturn(expr);
|
||||
}
|
||||
|
||||
public function executeWithVars(script:String, vars:Dynamic):Dynamic {
|
||||
var interp = clearPrevious ? getNewInterp() : this.interp;
|
||||
var expr = Util.parse(headerCode + script + tailCode);
|
||||
if(expr == null)
|
||||
return "ERROR";
|
||||
for(v in Reflect.fields(vars))
|
||||
interp.variables.set(v, Reflect.field(vars, v));
|
||||
if (clearPrevious)
|
||||
return interp.execute(expr);
|
||||
else
|
||||
return interp.exprReturn(expr);
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -3,16 +3,17 @@ import hscript.Expr.Error;
|
||||
using StringTools;
|
||||
|
||||
class Util {
|
||||
public static function assert(value:Bool, message:String) {
|
||||
public static function assert(value:Bool, message:String, ?pos:haxe.PosInfos) {
|
||||
if (value) {
|
||||
passedTestUnits++;
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message);
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
failedTestUnits++;
|
||||
}
|
||||
}
|
||||
|
||||
public static function assertEq(value:Dynamic, expected:Dynamic, message:String) {
|
||||
public static function assertEq(value:Dynamic, expected:Dynamic, message:String, ?pos:haxe.PosInfos) {
|
||||
var passed = value == expected;
|
||||
if (Std.isOfType(value, Array) && Std.isOfType(expected, Array)) {
|
||||
if (deepCompareArrays(value, expected))
|
||||
@@ -27,11 +28,12 @@ class Util {
|
||||
passedTestUnits++;
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message + " Expected: " + expected + " Got: " + value);
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
failedTestUnits++;
|
||||
}
|
||||
}
|
||||
|
||||
public static function assertNeq(value:Dynamic, expected:Dynamic, message:String) {
|
||||
public static function assertNeq(value:Dynamic, expected:Dynamic, message:String, ?pos:haxe.PosInfos) {
|
||||
var passed = value != expected;
|
||||
if (Std.isOfType(value, Array) && Std.isOfType(expected, Array)) {
|
||||
if (!deepCompareArrays(value, expected))
|
||||
@@ -44,6 +46,7 @@ class Util {
|
||||
passedTestUnits++;
|
||||
} else {
|
||||
Sys.println("Assertion failed: " + message + " Expected: " + expected + " Got: " + value);
|
||||
Sys.println("> At " + pos.fileName + ":" + pos.lineNumber);
|
||||
failedTestUnits++;
|
||||
}
|
||||
}
|
||||
@@ -154,7 +157,7 @@ class Util {
|
||||
var err = error.toString();
|
||||
if (err.startsWith(fn)) err = err.substr(fn.length);
|
||||
|
||||
Sys.println(fn + err);
|
||||
Sys.println("ERROR: " + fn + err);
|
||||
//Logs.traceColored([
|
||||
// Logs.logText(fn, GREEN),
|
||||
// Logs.logText(err, RED)
|
||||
|
||||
@@ -15,10 +15,10 @@ class TestBenchmark extends Benchmark {
|
||||
|
||||
public var a:Array<Float> = [];
|
||||
public override function haxeBenchmark() {
|
||||
for (i in 0...1000) a.push(i);
|
||||
for (i in 0...1000) a.push(i * 2 + 1 / 6);
|
||||
}
|
||||
|
||||
public override function hscriptBenchmark() {
|
||||
execute("var a:Array<Float> = []; for (i in 0...1000) a.push(i);");
|
||||
execute("var a:Array<Float> = []; for (i in 0...1000) a.push(i * 2 + 1 / 6);");
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,18 @@ class MiscCase extends TestCase {
|
||||
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);
|
||||
@@ -19,6 +31,108 @@ class MiscCase extends TestCase {
|
||||
|
||||
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("{ var x = 0; } x",55,{ x : 55 });
|
||||
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 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;});
|
||||
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 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 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);
|
||||
}
|
||||
|
||||
override function teardown() {
|
||||
|
||||
@@ -24,6 +24,7 @@ class SwitchCase extends TestCase {
|
||||
|
||||
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'; 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; });
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,23 @@ package tests;
|
||||
@:access(hscript.Interp)
|
||||
@:access(hscript.Parser)
|
||||
class TestCase extends HScriptRunner {
|
||||
public function assertEq(script:String, expected:Dynamic, ?message:String) {
|
||||
public function assertEq(script:String, expected:Dynamic, ?message:String, ?vars:Dynamic, ?pos:haxe.PosInfos) {
|
||||
if(message == null)
|
||||
message = script;
|
||||
Util.assertEq(execute(headerCode + script + tailCode), expected, message);
|
||||
var result = if(vars != null)
|
||||
executeWithVars(headerCode + script + tailCode, vars);
|
||||
else
|
||||
execute(headerCode + script + tailCode);
|
||||
Util.assertEq(result, expected, message, pos);
|
||||
}
|
||||
|
||||
public function assertNeq(script:String, expected:Dynamic, ?message:String) {
|
||||
public function assertNeq(script:String, expected:Dynamic, ?message:String, ?vars:Dynamic, ?pos:haxe.PosInfos) {
|
||||
if(message == null)
|
||||
message = script;
|
||||
Util.assertNeq(execute(headerCode + script + tailCode), expected, message);
|
||||
var result = if(vars != null)
|
||||
executeWithVars(headerCode + script + tailCode, vars);
|
||||
else
|
||||
execute(headerCode + script + tailCode);
|
||||
Util.assertNeq(result, expected, message, pos);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user