From 32fcb2378b5ebd4093e07e412aef60a8075d7cb8 Mon Sep 17 00:00:00 2001 From: Davvex87 Date: Tue, 22 Apr 2025 16:18:53 +0100 Subject: [PATCH 1/7] Unit Tests Replaces the old ugly Test.hx class with a new one that handles proper unit testing with assertion (utest library). --- Test.hx | 157 ++++++++++++++++++----------------------------------- build.hxml | 3 +- 2 files changed, 54 insertions(+), 106 deletions(-) diff --git a/Test.hx b/Test.hx index 695af0f..f57c73d 100644 --- a/Test.hx +++ b/Test.hx @@ -1,131 +1,78 @@ package; -import hscript.AbstractHScriptClass; +import utest.ITest; +import utest.Assert; +import hscript.*; class Test { static function main() { - // TODO: Make proper unit tests, this stinks + var runner = new utest.Runner(); - var parser = new hscript.SuperParser(); - var interp = new hscript.SuperInterp(); + runner.addCase(new TestHScriptFeatures()); + runner.addCase(new TestHScriptOOP()); - var script:String = " - package hscript; - - import haxe.ds.StringMap; - import haxe.io.Path; - - class TestClass extends TestClass - { - public static var hscriptStaticVar:Float = 2.7; - - static public function myStaticFunc(add:Float, mult:Float, div:Float = 1.3) - { - trace(hscriptStaticVar + add); - trace(hscriptStaticVar / div); - staticPrivateFunc(); - return hscriptStaticVar * mult; - } - - - - - public var hscriptVar:String = 'Hello World!'; - - public function new(num:Int, str:String) - { - trace('instanced!'); - trace(super); - super(); - trace(num); - trace(str); - trace(super); - } - - public function hscriptFunc(add:Float) - { - trace('hscript function called'); - trace(super.myVar + add); - } - - private function privateFunc() - { - trace('private func'); - trace(super.myFunc('bruh', 555555.5555)); - } - - private static function staticPrivateFunc() - { - mult = 10; // going to ignore this, should not happen; - trace('called the private function from static class'); - } - } - "; - trace("created interp and parser"); - - var program = parser.parseString(script, "TestScript.hx", 0 ); - trace("parsed script"); - parser.resumeErrors = true; - var declarations = parser.parseModule(script, "TestScript.hx", 0 ); - parser.resumeErrors = false; - trace("parsed modules"); - - trace("executing"); - - interp.execute(program); - - trace("registering structures"); - - interp.registerStructures(declarations); + utest.ui.Report.create(runner); + runner.run(); + } +} - trace("getting class"); +class TestHScriptFeatures implements ITest +{ + public function new() {} - var cls:AbstractHScriptClass = hscript.SuperInterp.resolveClass("hscript.TestClass"); - trace("got the class"); - - //try { trace(cls.hscriptStaticVar); } catch(e:Dynamic) { trace(e); } // works - //try { trace(cls.myStaticFunc(5, 3)); } catch(e:Dynamic) { trace(e); } // works, need to test to see if function arguments remain in the local variables list - //try { trace(cls.staticPrivateFunc()); } catch(e:Dynamic) { trace(e); } // works - // dont need to test for class extensions because static classes do not need to extend other classes + private function evalExpr(expr:String, ?params:Array):Dynamic + { + var parser = new SuperParser(); + var interp = new SuperInterp(); - var inst:AbstractHScriptClass = cls.createInstance(85, "hi"); + var program = parser.parseString(expr, '', 0); - try { trace(inst.hscriptVar); } catch(e:Dynamic) { trace(e); } - try { trace(inst.hscriptFunc(2.5)); } catch(e:Dynamic) { trace(e); } - try { trace(inst.privateFunc()); } catch(e:Dynamic) { trace(e); } - try { trace(inst.myVar); } catch(e:Dynamic) { trace(e); } - try { trace(inst.myFunc(123,456)); } catch(e:Dynamic) { trace(e); } - try { trace(inst.super.myFunc(123,456)); } catch(e:Dynamic) { trace(e); } - try { inst.myVar += 8; } catch(e:Dynamic) { trace(e); } - try { trace(inst.myVar); } catch(e:Dynamic) { trace(e); } - try { trace(inst.myPrivateFunc(1)); } catch(e:Dynamic) { trace(e); } + if (params != null) + interp.variables.set("params", params); - trace("DONE!"); + return interp.execute(program); } -} - -class TestClass -{ - public static var staticVar:Float = 9.30; - public var myVar:Int = 1; + function testArithmetic() + { + Assert.equals(7, evalExpr('3 + 4;')); + Assert.equals(14, evalExpr('3 * 4 + 2;')); + Assert.equals(4, evalExpr('16 / (7 - 3);')); + } - public function new() + function testConditions() { - trace("CONSTRUCTOR CALLED!!!"); + Assert.isTrue(evalExpr("3 > 1;")); + Assert.isTrue(evalExpr("3 >= 3;")); + Assert.isFalse(evalExpr("4 < 7 && 1 + 2 == 4;")); + Assert.isTrue(evalExpr("false || 1 % 2 == 1;")); + Assert.equals("I am at work", evalExpr("if (true == false) 'I am here'; else 'I am at work';")); + Assert.equals(3, evalExpr("false ? 10 : 3;")); } - public function myFunc(arg1:Dynamic, arg2:Dynamic, arg3:Dynamic) + function testStringInterpolation() { - trace('my function was called with args $arg1 $arg2 and $arg3'); - return 5; + Assert.equals("Hello, World!", evalExpr("'Hello, ${params[0]}!';", ["World"])); + Assert.equals("I have 5 coins", evalExpr("'I have ${3+2} coins';")); + Assert.equals("OneTwoThree", evalExpr("'${params[0]}${params[1]}${params[2]}';", ["One","Two","Three"])); } - private function myPrivateFunc() + function testAssignment() { - trace('my private function was called'); - return 'hello!'; + Assert.equals(7, evalExpr('var a = 5; a += 2;')); + Assert.equals('foo', evalExpr("var a:String = null; a ??= 'foo'; a;")); } + + function testOptionalChaining() + { + Assert.equals('ok', evalExpr('var a = { f: "ok" }; a?.f;')); + Assert.isNull(evalExpr('var a = null; a?.f;')); + } +} + +class TestHScriptOOP +{ + public function new() {} } \ No newline at end of file diff --git a/build.hxml b/build.hxml index 4c59a54..0934c64 100644 --- a/build.hxml +++ b/build.hxml @@ -1,6 +1,7 @@ --cp src -m Test +-cp test -lib hscript +-lib utest -D no-deprecation-warnings -D no-invalid-expression-warnings From cbedbf7c2c23e61225fbc0a33798dfc51dfcc8bf Mon Sep 17 00:00:00 2001 From: TechnikTil Date: Thu, 24 Apr 2025 15:02:39 -0600 Subject: [PATCH 2/7] add support for hl, js, and neko + fix hashlink --- build.hxml | 11 +---------- hscript/SuperInterp.hx | 2 +- test/.gitignore | 1 + test/build-base.hxml | 6 ++++++ test/build-hl.hxml | 2 ++ test/build-interp.hxml | 2 ++ test/build-js.hxml | 2 ++ test/build-neko.hxml | 2 ++ 8 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 test/.gitignore create mode 100644 test/build-base.hxml create mode 100644 test/build-hl.hxml create mode 100644 test/build-interp.hxml create mode 100644 test/build-js.hxml create mode 100644 test/build-neko.hxml diff --git a/build.hxml b/build.hxml index 0934c64..56987ca 100644 --- a/build.hxml +++ b/build.hxml @@ -1,11 +1,2 @@ --m Test --cp test --lib hscript --lib utest - --D no-deprecation-warnings --D no-invalid-expression-warnings --D hscriptPos - ---macro addGlobalMetadata('hscript', '@:build(hscript.macros.ParserMacro.buildAll())', false, true, false) +test/build-base.hxml --interp \ No newline at end of file diff --git a/hscript/SuperInterp.hx b/hscript/SuperInterp.hx index fa65f25..445748e 100644 --- a/hscript/SuperInterp.hx +++ b/hscript/SuperInterp.hx @@ -186,7 +186,7 @@ class SuperInterp extends ReInterp switch( #if hscriptPos x #else e #end ) { case EIdent(id): - var val = super.expr(e); + var val:Dynamic = super.expr(e); if (blacklist.contains(val)) error(ECustom('Blacklisted expression $val referenced')); case _: diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..9eda26c --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +Build.* \ No newline at end of file diff --git a/test/build-base.hxml b/test/build-base.hxml new file mode 100644 index 0000000..8c39569 --- /dev/null +++ b/test/build-base.hxml @@ -0,0 +1,6 @@ +extraParams.hxml +-m Test +-lib utest + +-D no-deprecation-warnings +-D no-invalid-expression-warnings \ No newline at end of file diff --git a/test/build-hl.hxml b/test/build-hl.hxml new file mode 100644 index 0000000..e7fc90c --- /dev/null +++ b/test/build-hl.hxml @@ -0,0 +1,2 @@ +test/build-base.hxml +--hl test/Build.hl \ No newline at end of file diff --git a/test/build-interp.hxml b/test/build-interp.hxml new file mode 100644 index 0000000..56987ca --- /dev/null +++ b/test/build-interp.hxml @@ -0,0 +1,2 @@ +test/build-base.hxml +--interp \ No newline at end of file diff --git a/test/build-js.hxml b/test/build-js.hxml new file mode 100644 index 0000000..4a34e3d --- /dev/null +++ b/test/build-js.hxml @@ -0,0 +1,2 @@ +test/build-base.hxml +--js test/Build.js \ No newline at end of file diff --git a/test/build-neko.hxml b/test/build-neko.hxml new file mode 100644 index 0000000..ba21461 --- /dev/null +++ b/test/build-neko.hxml @@ -0,0 +1,2 @@ +test/build-base.hxml +--neko test/Build.n \ No newline at end of file From d23267a3b50a66cad8423078f0af101c6a7389e4 Mon Sep 17 00:00:00 2001 From: Davvex87 Date: Thu, 8 May 2025 11:36:30 +0100 Subject: [PATCH 3/7] Updated Test.hx to feature even more features --- Test.hx | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Test.hx b/Test.hx index f57c73d..dc8801d 100644 --- a/Test.hx +++ b/Test.hx @@ -22,7 +22,7 @@ class TestHScriptFeatures implements ITest { public function new() {} - private function evalExpr(expr:String, ?params:Array):Dynamic + private function evalExpr(expr:String, ?vars: Map, ?params:Array):Dynamic { var parser = new SuperParser(); var interp = new SuperInterp(); @@ -32,6 +32,14 @@ class TestHScriptFeatures implements ITest if (params != null) interp.variables.set("params", params); + if (vars != null) + { + for (key => value in vars) + { + interp.variables.set(key, value); + } + } + return interp.execute(program); } @@ -70,9 +78,71 @@ class TestHScriptFeatures implements ITest Assert.equals('ok', evalExpr('var a = { f: "ok" }; a?.f;')); Assert.isNull(evalExpr('var a = null; a?.f;')); } + + function testFields() + { + Assert.equals(5.5, evalExpr("TestObj.myVar;", ["TestObj"=>TestObj])); + Assert.equals("3 apples", evalExpr("TestObj.testFunc(3, 'apple');", ["TestObj"=>TestObj])); + Assert.equals(2, evalExpr("var t = new TestObj(); t.secretCode[2];", ["TestObj"=>TestObj])); + Assert.equals("SECRET_CODE", evalExpr("var t = new TestObj(); t.getRecovery();", ["TestObj"=>TestObj])); + + var obj:Dynamic = evalExpr("return { n1: 5, others: {o1: true, o2: 'NO!'}}"); + + Assert.equals(5, obj.n1); + Assert.isTrue(obj.others.o1); + evalExpr("obj.others.o2 = 'YES!'", ["obj"=>obj]); + Assert.equals("YES!", obj.others.o2); + } + + function testFunctions() + { + var fn:Dynamic = evalExpr('function(arg1, num) { return arg1 + num; }'); + if (Type.typeof(fn) == Type.ValueType.TFunction) + Assert.pass("fn correctly declared as a function"); + else + Assert.fail("fn test failed, function not declared"); + + Assert.equals(7, fn(3, 4)); + Assert.equals("Hi", fn("H", "i")); + + var fn2:Dynamic = evalExpr('function(obj) {obj.a = true; obj.n.b += 3;}'); + if (Type.typeof(fn2) == Type.ValueType.TFunction) + Assert.pass("fn2 correctly declared as a function"); + else + Assert.fail("fn2 test failed, function not declared"); + + var obj = { + a: false, + n: { + b: 2 + } + } + + fn2(obj); + + Assert.isTrue(obj.a); + Assert.equals(5, obj.n.b); + } } class TestHScriptOOP { public function new() {} +} + +class TestObj +{ + public static var myVar:Float = 5.5; + public static function testFunc(num:Int, fruit:String) + { + return '$num ${fruit}s'; + } + + public function new() {} + + public var secretCode:Array = [4,3,2,1]; + public function getRecovery() + { + return "SECRET_CODE"; + } } \ No newline at end of file From 9a560c8fc1921bfc7b6ce0a323e4a3d321870320 Mon Sep 17 00:00:00 2001 From: Davvex87 Date: Thu, 8 May 2025 11:43:04 +0100 Subject: [PATCH 4/7] Indentation fix --- Test.hx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Test.hx b/Test.hx index dc8801d..522a8d0 100644 --- a/Test.hx +++ b/Test.hx @@ -75,24 +75,24 @@ class TestHScriptFeatures implements ITest function testOptionalChaining() { - Assert.equals('ok', evalExpr('var a = { f: "ok" }; a?.f;')); - Assert.isNull(evalExpr('var a = null; a?.f;')); - } + Assert.equals('ok', evalExpr('var a = { f: "ok" }; a?.f;')); + Assert.isNull(evalExpr('var a = null; a?.f;')); + } function testFields() - { - Assert.equals(5.5, evalExpr("TestObj.myVar;", ["TestObj"=>TestObj])); - Assert.equals("3 apples", evalExpr("TestObj.testFunc(3, 'apple');", ["TestObj"=>TestObj])); - Assert.equals(2, evalExpr("var t = new TestObj(); t.secretCode[2];", ["TestObj"=>TestObj])); - Assert.equals("SECRET_CODE", evalExpr("var t = new TestObj(); t.getRecovery();", ["TestObj"=>TestObj])); + { + Assert.equals(5.5, evalExpr("TestObj.myVar;", ["TestObj"=>TestObj])); + Assert.equals("3 apples", evalExpr("TestObj.testFunc(3, 'apple');", ["TestObj"=>TestObj])); + Assert.equals(2, evalExpr("var t = new TestObj(); t.secretCode[2];", ["TestObj"=>TestObj])); + Assert.equals("SECRET_CODE", evalExpr("var t = new TestObj(); t.getRecovery();", ["TestObj"=>TestObj])); - var obj:Dynamic = evalExpr("return { n1: 5, others: {o1: true, o2: 'NO!'}}"); + var obj:Dynamic = evalExpr("return { n1: 5, others: {o1: true, o2: 'NO!'}}"); - Assert.equals(5, obj.n1); - Assert.isTrue(obj.others.o1); - evalExpr("obj.others.o2 = 'YES!'", ["obj"=>obj]); - Assert.equals("YES!", obj.others.o2); - } + Assert.equals(5, obj.n1); + Assert.isTrue(obj.others.o1); + evalExpr("obj.others.o2 = 'YES!'", ["obj"=>obj]); + Assert.equals("YES!", obj.others.o2); + } function testFunctions() { From ba50c8688aecf19f7718609a9fe1ea4389b8dfa7 Mon Sep 17 00:00:00 2001 From: Davvex87 Date: Thu, 8 May 2025 17:11:16 +0100 Subject: [PATCH 5/7] Organized test code & added a few more test functions --- Test.hx | 145 ++----------------- test/build-base.hxml | 1 + test/source/Shared.hx | 22 +++ test/source/cases/ClassFeaturesCase.hx | 10 ++ test/source/cases/LanguageFeaturesCase.hx | 164 ++++++++++++++++++++++ test/source/modules/TestObj.hx | 18 +++ 6 files changed, 224 insertions(+), 136 deletions(-) create mode 100644 test/source/Shared.hx create mode 100644 test/source/cases/ClassFeaturesCase.hx create mode 100644 test/source/cases/LanguageFeaturesCase.hx create mode 100644 test/source/modules/TestObj.hx diff --git a/Test.hx b/Test.hx index 522a8d0..288dc4b 100644 --- a/Test.hx +++ b/Test.hx @@ -1,148 +1,21 @@ package; -import utest.ITest; -import utest.Assert; -import hscript.*; +import utest.Runner; +import utest.ui.Report; + +import cases.ClassFeaturesCase; +import cases.LanguageFeaturesCase; class Test { static function main() { - var runner = new utest.Runner(); + var runner = new Runner(); - runner.addCase(new TestHScriptFeatures()); - runner.addCase(new TestHScriptOOP()); + runner.addCase(new LanguageFeaturesCase()); + runner.addCase(new ClassFeaturesCase()); - utest.ui.Report.create(runner); + Report.create(runner); runner.run(); } -} - -class TestHScriptFeatures implements ITest -{ - public function new() {} - - private function evalExpr(expr:String, ?vars: Map, ?params:Array):Dynamic - { - var parser = new SuperParser(); - var interp = new SuperInterp(); - - var program = parser.parseString(expr, '', 0); - - if (params != null) - interp.variables.set("params", params); - - if (vars != null) - { - for (key => value in vars) - { - interp.variables.set(key, value); - } - } - - return interp.execute(program); - } - - function testArithmetic() - { - Assert.equals(7, evalExpr('3 + 4;')); - Assert.equals(14, evalExpr('3 * 4 + 2;')); - Assert.equals(4, evalExpr('16 / (7 - 3);')); - } - - function testConditions() - { - Assert.isTrue(evalExpr("3 > 1;")); - Assert.isTrue(evalExpr("3 >= 3;")); - Assert.isFalse(evalExpr("4 < 7 && 1 + 2 == 4;")); - Assert.isTrue(evalExpr("false || 1 % 2 == 1;")); - Assert.equals("I am at work", evalExpr("if (true == false) 'I am here'; else 'I am at work';")); - Assert.equals(3, evalExpr("false ? 10 : 3;")); - } - - function testStringInterpolation() - { - Assert.equals("Hello, World!", evalExpr("'Hello, ${params[0]}!';", ["World"])); - Assert.equals("I have 5 coins", evalExpr("'I have ${3+2} coins';")); - Assert.equals("OneTwoThree", evalExpr("'${params[0]}${params[1]}${params[2]}';", ["One","Two","Three"])); - } - - function testAssignment() - { - Assert.equals(7, evalExpr('var a = 5; a += 2;')); - Assert.equals('foo', evalExpr("var a:String = null; a ??= 'foo'; a;")); - } - - function testOptionalChaining() - { - Assert.equals('ok', evalExpr('var a = { f: "ok" }; a?.f;')); - Assert.isNull(evalExpr('var a = null; a?.f;')); - } - - function testFields() - { - Assert.equals(5.5, evalExpr("TestObj.myVar;", ["TestObj"=>TestObj])); - Assert.equals("3 apples", evalExpr("TestObj.testFunc(3, 'apple');", ["TestObj"=>TestObj])); - Assert.equals(2, evalExpr("var t = new TestObj(); t.secretCode[2];", ["TestObj"=>TestObj])); - Assert.equals("SECRET_CODE", evalExpr("var t = new TestObj(); t.getRecovery();", ["TestObj"=>TestObj])); - - var obj:Dynamic = evalExpr("return { n1: 5, others: {o1: true, o2: 'NO!'}}"); - - Assert.equals(5, obj.n1); - Assert.isTrue(obj.others.o1); - evalExpr("obj.others.o2 = 'YES!'", ["obj"=>obj]); - Assert.equals("YES!", obj.others.o2); - } - - function testFunctions() - { - var fn:Dynamic = evalExpr('function(arg1, num) { return arg1 + num; }'); - if (Type.typeof(fn) == Type.ValueType.TFunction) - Assert.pass("fn correctly declared as a function"); - else - Assert.fail("fn test failed, function not declared"); - - Assert.equals(7, fn(3, 4)); - Assert.equals("Hi", fn("H", "i")); - - var fn2:Dynamic = evalExpr('function(obj) {obj.a = true; obj.n.b += 3;}'); - if (Type.typeof(fn2) == Type.ValueType.TFunction) - Assert.pass("fn2 correctly declared as a function"); - else - Assert.fail("fn2 test failed, function not declared"); - - var obj = { - a: false, - n: { - b: 2 - } - } - - fn2(obj); - - Assert.isTrue(obj.a); - Assert.equals(5, obj.n.b); - } -} - -class TestHScriptOOP -{ - public function new() {} -} - -class TestObj -{ - public static var myVar:Float = 5.5; - public static function testFunc(num:Int, fruit:String) - { - return '$num ${fruit}s'; - } - - public function new() {} - - public var secretCode:Array = [4,3,2,1]; - public function getRecovery() - { - return "SECRET_CODE"; - } } \ No newline at end of file diff --git a/test/build-base.hxml b/test/build-base.hxml index 8c39569..171b9ee 100644 --- a/test/build-base.hxml +++ b/test/build-base.hxml @@ -1,6 +1,7 @@ extraParams.hxml -m Test -lib utest +-cp test/source -D no-deprecation-warnings -D no-invalid-expression-warnings \ No newline at end of file diff --git a/test/source/Shared.hx b/test/source/Shared.hx new file mode 100644 index 0000000..c0df525 --- /dev/null +++ b/test/source/Shared.hx @@ -0,0 +1,22 @@ +import hscript.*; + +function evalExpr(expr:String, ?vars: Map, ?params:Array):Dynamic +{ + var parser = new SuperParser(); + var interp = new SuperInterp(); + + var program = parser.parseString(expr, '', 0); + + if (params != null) + interp.variables.set("params", params); + + if (vars != null) + { + for (key => value in vars) + { + interp.variables.set(key, value); + } + } + + return interp.execute(program); +} \ No newline at end of file diff --git a/test/source/cases/ClassFeaturesCase.hx b/test/source/cases/ClassFeaturesCase.hx new file mode 100644 index 0000000..841e660 --- /dev/null +++ b/test/source/cases/ClassFeaturesCase.hx @@ -0,0 +1,10 @@ +package cases; + +import utest.ITest; +import utest.Assert; +import hscript.*; + +class ClassFeaturesCase implements ITest +{ + public function new() {} +} \ No newline at end of file diff --git a/test/source/cases/LanguageFeaturesCase.hx b/test/source/cases/LanguageFeaturesCase.hx new file mode 100644 index 0000000..5b074ac --- /dev/null +++ b/test/source/cases/LanguageFeaturesCase.hx @@ -0,0 +1,164 @@ +package cases; + +import modules.TestObj; +import Shared; + +import utest.ITest; +import utest.Assert; + +/** + * Test suite class for ensuring language features work correctly. + * It provides test functions for vanilla HScript features and also Super-HScript specific features. + */ +class LanguageFeaturesCase implements ITest +{ + public function new() {} + + /** + * Tests basic mathematic operators. + */ + function testArithmetic() + { + Assert.equals(7, evalExpr('3 + 4;')); + Assert.equals(14, evalExpr('3 * 4 + 2;')); + Assert.equals(4, evalExpr('16 / (7 - 3);')); + } + + /** + * Tests conditions with boolean algebra. + */ + function testConditions() + { + Assert.isTrue(evalExpr("3 > 1;")); + Assert.isTrue(evalExpr("3 >= 3;")); + Assert.isFalse(evalExpr("4 < 7 && 1 + 2 == 4;")); + Assert.isTrue(evalExpr("false || 1 % 2 == 1;")); + Assert.equals("I am at work", evalExpr("if (true == false) 'I am here'; else 'I am at work';")); + Assert.equals(3, evalExpr("false ? 10 : 3;")); + } + + /** + * Tests for string interpolation. + */ + function testStringInterpolation() + { + Assert.equals("Hello, World!", evalExpr("'Hello, ${params[0]}!';", ["World"])); + Assert.equals("I have 5 coins", evalExpr("'I have ${3+2} coins';")); + Assert.equals("OneTwoThree", evalExpr("'${params[0]}${params[1]}${params[2]}';", ["One","Two","Three"])); + } + + /** + * Tests the var operator, local assignments and other special assignment operators. + */ + function testAssignment() + { + Assert.equals(7, evalExpr('var a = 5; a += 2;')); + Assert.equals('foo', evalExpr("var a:String = null; a ??= 'foo'; a;")); + } + + /** + * Tests optional chaining expressions. + */ + function testOptionalChaining() + { + Assert.equals('ok', evalExpr('var a = { f: "ok" }; a?.f;')); + Assert.isNull(evalExpr('var a = null; a?.f;')); + } + + /** + * Tests for field write and read operations on both anonymous structures and class objects. + */ + function testFields() + { + Assert.equals(5.5, evalExpr("TestObj.myVar;", ["TestObj"=>TestObj])); + Assert.equals("3 apples", evalExpr("TestObj.testFunc(3, 'apple');", ["TestObj"=>TestObj])); + Assert.equals(2, evalExpr("var t = new TestObj(); t.secretCode[2];", ["TestObj"=>TestObj])); + Assert.equals("SECRET_CODE", evalExpr("var t = new TestObj(); t.getRecovery();", ["TestObj"=>TestObj])); + + var obj:Dynamic = evalExpr("{ n1: 5, others: {o1: true, o2: 'NO!'}}"); + + Assert.equals(5, obj.n1); + Assert.isTrue(obj.others.o1); + evalExpr("obj.others.o2 = 'YES!'", ["obj"=>obj]); + Assert.equals("YES!", obj.others.o2); + } + + /** + * Tests function definitions, function calls and function arguments. + * Type definitions are ignored. + */ + function testFunctions() + { + // First test: Tests for declaring a function and calling it from Haxe with some arguments. + + var fn:Dynamic = evalExpr('function(arg1, num) { return arg1 + num; }'); + if (Type.typeof(fn) == Type.ValueType.TFunction) + Assert.pass("fn correctly declared as a function"); + else + Assert.fail("fn test failed, function not declared"); + + Assert.equals(7, fn(3, 4)); + Assert.equals("Hi", fn("H", "i")); + + + // Second test: Tests for modifications on objects not present to the locals map. + + var fn2:Dynamic = evalExpr('function(obj) {obj.a = true; obj.n.b += 3;}'); + if (Type.typeof(fn2) == Type.ValueType.TFunction) + Assert.pass("fn2 correctly declared as a function"); + else + Assert.fail("fn2 test failed, function not declared"); + + var obj = { + a: false, + n: { + b: 2 + } + } + + fn2(obj); + + Assert.isTrue(obj.a); + Assert.equals(5, obj.n.b); + } + + /** + * Tests for while, do-while, for and recursion loops. + */ + function testLoops() + { + // For loops + Assert.equals(1024, evalExpr('var o = 1; for (i in 0...10) o *= 2; o;')); + + // While and Do-While loops + Assert.equals(9, evalExpr('var o = 0; while (o < 9) o+=1; o;')); + Assert.equals(-1, evalExpr('var o = 0; do o-=1 while (o > 0); o;')); + Assert.equals(0, evalExpr('var o = 3; do o-=1 while (o > 0); o;')); + Assert.equals(0, evalExpr('var o = 0; while (o > 0) o-=1; o;')); + Assert.equals(-3, evalExpr('var o = -3; while (o > 0) o-=1; o;')); + + // Recursion loops + try + { Assert.equals(9, evalExpr('var o = 0; function r() { if (o >= 9) return o; o+=1; return r(); } r();')); } + catch(e:Dynamic) + Assert.fail("function recursed forever"); + } + + /** + * Tests for basic iterators. + */ + function testIterators() + { + Assert.equals(6, evalExpr('var o = 0; for (i in [1, 2, 3]) o+=i; o;')); + } + + + + // TODO + + function testPartialFunction() {} + function testProperties() {} + function testDefines() {} + function testGADT() {} + function testPatternMatching() {} +} \ No newline at end of file diff --git a/test/source/modules/TestObj.hx b/test/source/modules/TestObj.hx new file mode 100644 index 0000000..4b2493c --- /dev/null +++ b/test/source/modules/TestObj.hx @@ -0,0 +1,18 @@ +package modules; + +class TestObj +{ + public static var myVar:Float = 5.5; + public static function testFunc(num:Int, fruit:String) + { + return '$num ${fruit}s'; + } + + public function new() {} + + public var secretCode:Array = [4,3,2,1]; + public function getRecovery() + { + return "SECRET_CODE"; + } +} \ No newline at end of file From 3fc2534e906e5a1bad44daa8944303a63eed10b3 Mon Sep 17 00:00:00 2001 From: Davvex87 Date: Fri, 9 May 2025 23:31:43 +0100 Subject: [PATCH 6/7] evalFile function for classes --- test/source/Shared.hx | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/test/source/Shared.hx b/test/source/Shared.hx index c0df525..48e3005 100644 --- a/test/source/Shared.hx +++ b/test/source/Shared.hx @@ -1,3 +1,5 @@ +import haxe.io.Path; +import sys.io.File; import hscript.*; function evalExpr(expr:String, ?vars: Map, ?params:Array):Dynamic @@ -11,12 +13,27 @@ function evalExpr(expr:String, ?vars: Map, ?params:Array value in vars) - { interp.variables.set(key, value); - } - } + + return interp.execute(program); +} + +function evalFile(file:String, ?vars:Map):Dynamic +{ + var expr = File.getContent(file); + var fname = Path.withoutDirectory(file); + + var parser = new SuperParser(); + var interp = new SuperInterp(); + + var program = parser.parseString(expr, fname, 0); + var modules = parser.parseModule(expr, fname, 0); + + if (vars != null) + for (key => value in vars) + interp.variables.set(key, value); + interp.registerStructures(modules, file); return interp.execute(program); } \ No newline at end of file From 458b536c587260d7f87336308ceced58ae868411 Mon Sep 17 00:00:00 2001 From: Davvex87 Date: Wed, 6 Aug 2025 21:07:03 +0100 Subject: [PATCH 7/7] Parser Macro dupe fix --- hscript/macros/ParserMacro.hx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hscript/macros/ParserMacro.hx b/hscript/macros/ParserMacro.hx index 1e0ae23..32e2be9 100644 --- a/hscript/macros/ParserMacro.hx +++ b/hscript/macros/ParserMacro.hx @@ -38,18 +38,23 @@ class ParserMacro function makeEnumField(name, kind):Field { - return { + for (f in fields) + if (f.name == name) + return null; + + var field:Field = { name: name, doc: null, meta: [], access: [], kind: kind, pos: Context.currentPos() - } + }; + fields.push(field); + return field; } - fields.push( - makeEnumField("TApostr", FVar(null, null)) - ); + + makeEnumField("TApostr", FVar(null, null)); case _: }