From a29f2934d94240fa38a324cdeab5b60744ebc39b Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Thu, 28 Oct 2021 14:48:23 -0400 Subject: [PATCH] allow catch in defMacro without :Dynamic --- kiss/src/kiss/Helpers.hx | 49 ++++++++++++++++++++++++-- kiss/src/kiss/Kiss.hx | 3 ++ kiss/src/kiss/KissInterp.hx | 5 +-- kiss/src/kiss/Macros.hx | 2 +- kiss/src/test/cases/MacroTestCase.hx | 4 +++ kiss/src/test/cases/MacroTestCase.kiss | 6 ++++ 6 files changed, 64 insertions(+), 5 deletions(-) diff --git a/kiss/src/kiss/Helpers.hx b/kiss/src/kiss/Helpers.hx index 5d4a179c..4b58527e 100644 --- a/kiss/src/kiss/Helpers.hx +++ b/kiss/src/kiss/Helpers.hx @@ -21,6 +21,7 @@ using kiss.Reader; using kiss.Helpers; using kiss.Kiss; using StringTools; +using haxe.macro.ExprTools; /** * Compile-time helper functions for Kiss. Don't import or reference these at runtime. @@ -332,14 +333,58 @@ class Helpers { // When we ARE running at compiletime already, the pre-existing interp will be used static var interps:kiss.List = []; + public static function removeTypeAnnotations(exp:ReaderExp):ReaderExp { + var def = switch (exp.def) { + case Symbol(_) | StrExp(_) | RawHaxe(_) | Quasiquote(_): + exp.def; + case CallExp(func, callArgs): + CallExp(removeTypeAnnotations(func), callArgs.map(removeTypeAnnotations)); + case ListExp(elements): + ListExp(elements.map(removeTypeAnnotations)); + case TypedExp(type, innerExp): + innerExp.def; + case MetaExp(meta, innerExp): + MetaExp(meta, removeTypeAnnotations(innerExp)); + case FieldExp(field, innerExp): + FieldExp(field, removeTypeAnnotations(innerExp)); + case KeyValueExp(keyExp, valueExp): + KeyValueExp(removeTypeAnnotations(keyExp), removeTypeAnnotations(valueExp)); + default: + throw CompileError.fromExp(exp, 'cannot remove type annotations'); + }; + return def.withPosOf(exp); + } + // hscript.Interp is very finicky about some edge cases. + // This function handles them + private static function mapForInterp(expr:Expr):Expr { + return expr.map(subExp -> { + switch (subExp.expr) { + case ETry(e, catches): + catches = [for (c in catches) { + // hscript.Parser expects :Dynamic after the catch varname + { + type: Helpers.parseComplexType("Dynamic"), + name: c.name, + expr: c.expr + }; + }]; + { + pos: subExp.pos, + expr: ETry(e, catches) + }; + default: subExp; + } + }); + } + public static function runAtCompileTimeDynamic(exp:ReaderExp, k:KissState, ?args:Map):Dynamic { - var code = k.forHScript().convert(exp).toString(); // tink_macro to the rescue + var hscriptExp = mapForInterp(k.forHScript().convert(exp)); + var code = hscriptExp.toString(); // tink_macro to the rescue #if macrotest Prelude.print("Compile-time hscript: " + code); #end // Need parser external to the KissInterp to wrap parsing in an informative try-catch var parser = new Parser(); - parser.allowTypes = true; if (interps.length == 0) { var interp = new KissInterp(); interp.variables.set("read", Reader.assertRead.bind(_, k)); diff --git a/kiss/src/kiss/Kiss.hx b/kiss/src/kiss/Kiss.hx index f642f2f1..d37e5a90 100644 --- a/kiss/src/kiss/Kiss.hx +++ b/kiss/src/kiss/Kiss.hx @@ -283,6 +283,9 @@ class Kiss { // Bind the table arguments of this function for easy recursive calling/passing var convert = readerExpToHaxeExpr.bind(_, k); + if (k.hscript) + exp = Helpers.removeTypeAnnotations(exp); + var none = EBlock([]).withMacroPosOf(exp); var expr = switch (exp.def) { diff --git a/kiss/src/kiss/KissInterp.hx b/kiss/src/kiss/KissInterp.hx index 5680ab4f..1bd40829 100644 --- a/kiss/src/kiss/KissInterp.hx +++ b/kiss/src/kiss/KissInterp.hx @@ -2,8 +2,11 @@ package kiss; import hscript.Parser; import hscript.Interp; +import hscript.Expr; import kiss.Prelude; +using hscript.Tools; + /** * Specialized hscript interpreter for hscript generated from Kiss expressions. * When macrotest is defined by the compiler, many functions run without @@ -19,8 +22,6 @@ class KissInterp extends Interp { public function new(nullForUnknownVar = false) { super(); - parser.allowTypes = true; - this.nullForUnknownVar = nullForUnknownVar; variables.set("Reflect", Reflect); diff --git a/kiss/src/kiss/Macros.hx b/kiss/src/kiss/Macros.hx index 97924536..61aa8072 100644 --- a/kiss/src/kiss/Macros.hx +++ b/kiss/src/kiss/Macros.hx @@ -198,7 +198,7 @@ class Macros { #if test Prelude.print("#case hscript: " + hscriptStr); #end - return caseInterp.evalHaxe(caseStr); + return caseInterp.evalHaxe(hscriptStr); } catch (e) { throw CompileError.fromExp(caseExp, '#case evaluation threw error $e'); } diff --git a/kiss/src/test/cases/MacroTestCase.hx b/kiss/src/test/cases/MacroTestCase.hx index f32a8e9b..a02642a2 100644 --- a/kiss/src/test/cases/MacroTestCase.hx +++ b/kiss/src/test/cases/MacroTestCase.hx @@ -44,4 +44,8 @@ class MacroTestCase extends Test { function testSetMacroVar() { _testSetMacroVar(); } + + function testTryCatchWithoutDynamic () { + _testTryCatchWithoutDynamic(); + } } diff --git a/kiss/src/test/cases/MacroTestCase.kiss b/kiss/src/test/cases/MacroTestCase.kiss index 69e990cd..5e70ef4b 100644 --- a/kiss/src/test/cases/MacroTestCase.kiss +++ b/kiss/src/test/cases/MacroTestCase.kiss @@ -90,3 +90,9 @@ (function _testIfLetDisabled [] (_testIfLetDisabledMacro)) + +(defMacro _testTryCatchWithoutDynamicMacro [] + (try (throw "intended") (catch [e] (ReaderExp.StrExp e)))) + +(function _testTryCatchWithoutDynamic [] + (Assert.equals "intended" (_testTryCatchWithoutDynamicMacro))) \ No newline at end of file