diff --git a/kiss/src/kiss/Kiss.hx b/kiss/src/kiss/Kiss.hx index 1ea1816e..565b09df 100644 --- a/kiss/src/kiss/Kiss.hx +++ b/kiss/src/kiss/Kiss.hx @@ -16,6 +16,7 @@ import kiss.SpecialForms; import kiss.Macros; import kiss.KissError; import kiss.cloner.Cloner; +import tink.syntaxhub.*; using kiss.Kiss; using kiss.Helpers; @@ -68,11 +69,11 @@ typedef KissState = { class Kiss { #if macro - public static function defaultKissState(?name):KissState { - var className = if(name == null){ + public static function defaultKissState(?context:FrontendContext):KissState { + var className = if (context == null) { Context.getLocalClass().get().name; - }else{ - name; + } else { + context.name; } var k = { className: className, @@ -192,7 +193,7 @@ class Kiss { }; FieldForms.addBuiltins(k); - k.specialForms = SpecialForms.builtins(k); + k.specialForms = SpecialForms.builtins(k, context); k.macros = Macros.builtins(k); return k; @@ -276,7 +277,7 @@ class Kiss { /** Build macro: add fields to a class from a corresponding .kiss file **/ - public static function build(?kissFile:String, ?k:KissState, useClassFields = true, ?className:String):Array { + public static function build(?kissFile:String, ?k:KissState, useClassFields = true, ?context:FrontendContext):Array { var classPath = Context.getPosInfos(Context.currentPos()).file; // (load... ) relative to the original file @@ -292,7 +293,7 @@ class Kiss { trace(kissFile); #end if (k == null) - k = defaultKissState(className); + k = defaultKissState(context); if (useClassFields) { k.fieldList = Context.getBuildFields(); diff --git a/kiss/src/kiss/KissFrontend.hx b/kiss/src/kiss/KissFrontend.hx index c169b467..09c4f730 100644 --- a/kiss/src/kiss/KissFrontend.hx +++ b/kiss/src/kiss/KissFrontend.hx @@ -14,16 +14,19 @@ class KissFrontend implements FrontendPlugin { return ['kiss'].iterator(); public function parse(file:String, context:FrontendContext):Void { - - final fields = Kiss.build(file,null,false,context.name); - var pos = Context.makePosition({ file: file, min: 0, max: 999 }); - #if debug trace(context.name); #end - final type = context.getType(); - context.addImport('kiss.Prelude',INormal,pos); - for (field in fields){ + + final fields = Kiss.build(file,null,false,context); + #if debug + trace(context.name); + #end + final type = context.getType(); + var pos = Context.makePosition({ file: file, min: 0, max: 0 }); + context.addImport('kiss.Prelude',INormal,pos); + for (field in fields) { type.fields.push(field); } } + static function use() tink.SyntaxHub.frontends.whenever(new KissFrontend()); } \ No newline at end of file diff --git a/kiss/src/kiss/SpecialForms.hx b/kiss/src/kiss/SpecialForms.hx index 7a44cdad..16ea0ebc 100644 --- a/kiss/src/kiss/SpecialForms.hx +++ b/kiss/src/kiss/SpecialForms.hx @@ -13,12 +13,13 @@ using kiss.Helpers; using kiss.Prelude; using kiss.Kiss; using tink.MacroApi; +import tink.syntaxhub.*; // Special forms convert Kiss reader expressions into Haxe macro expressions typedef SpecialFormFunction = (wholeExp:ReaderExp, args:Array, k:KissState) -> Expr; class SpecialForms { - public static function builtins(k:KissState) { + public static function builtins(k:KissState, ?context:FrontendContext) { var map:Map = []; function renameAndDeprecate(oldName:String, newName:String) { @@ -537,6 +538,48 @@ class SpecialForms { return e; }; + function requireContext(exp, formName) { + if (context == null) { + throw KissError.fromExp(exp, '$formName cannot be used when calling Kiss as a build macro in a Haxe file.'); + } + } + + function none(exp) { + return EBlock([]).withMacroPosOf(exp); + } + + k.doc("import", 1, null, "(import )"); + map["import"] = (wholeExp:ReaderExp, exps:Array, k:KissState) -> { + requireContext(wholeExp, "import"); + for (type in exps) { + context.addImport(Reader.toString(type.def), INormal, wholeExp.macroPos()); + } + return none(wholeExp); + }; + + k.doc("importAs", 2, 2, "(importAs )"); + map["importAs"] = (wholeExp:ReaderExp, exps:Array, k:KissState) -> { + requireContext(wholeExp, "importAs"); + context.addImport(Reader.toString(exps[0].def), IAsName(Reader.toString(exps[1].def)), wholeExp.macroPos()); + return none(wholeExp); + }; + + k.doc("importAll", 1, 1, "(importAll )"); + map["importAll"] = (wholeExp:ReaderExp, exps:Array, k:KissState) -> { + requireContext(wholeExp, "importAll"); + context.addImport(Reader.toString(exps[0].def), IAll, wholeExp.macroPos()); + return none(wholeExp); + }; + + k.doc("using", 1, null, "(using )"); + map["using"] = (wholeExp:ReaderExp, exps:Array, k:KissState) -> { + requireContext(wholeExp, "using"); + for (type in exps) { + context.addUsing(Reader.toString(type.def), wholeExp.macroPos()); + } + return none(wholeExp); + }; + return map; } diff --git a/kiss/src/test/OtherPureKissClass.kiss b/kiss/src/test/OtherPureKissClass.kiss new file mode 100644 index 00000000..aca82f25 --- /dev/null +++ b/kiss/src/test/OtherPureKissClass.kiss @@ -0,0 +1,3 @@ +(function extensionMethod [:String s] "EXTENDED") + +(defNew [&prop :Int num]) \ No newline at end of file diff --git a/kiss/src/test/PureKissClass.kiss b/kiss/src/test/PureKissClass.kiss new file mode 100644 index 00000000..c4dc227c --- /dev/null +++ b/kiss/src/test/PureKissClass.kiss @@ -0,0 +1,9 @@ +(import test.OtherPureKissClass) +(importAs test.OtherPureKissClass Alias) +(using test.OtherPureKissClass) + +(function test [] + (assert (= (.extensionMethod "string") "EXTENDED")) + (let [instance (new OtherPureKissClass 5) + other (new Alias 5)] + (assert (= instance.num other.num 5)))) \ No newline at end of file diff --git a/kiss/src/test/cases/BasicTestCase.hx b/kiss/src/test/cases/BasicTestCase.hx index 116db853..1b7c4fb5 100644 --- a/kiss/src/test/cases/BasicTestCase.hx +++ b/kiss/src/test/cases/BasicTestCase.hx @@ -364,9 +364,17 @@ class BasicTestCase extends Test { _testQuickFractions(); } - function testWhenLetGuards() { + function testWhenLetGuards() { _testWhenLetGuards(); - } + } + + function testImportAndUsingInBuildMacro() { + _testImportAndUsingInBuildMacro(); + } + + function testPureKissClasses() { + _testPureKissClasses(); + } } diff --git a/kiss/src/test/cases/BasicTestCase.kiss b/kiss/src/test/cases/BasicTestCase.kiss index 553238e1..60afbb5a 100644 --- a/kiss/src/test/cases/BasicTestCase.kiss +++ b/kiss/src/test/cases/BasicTestCase.kiss @@ -693,4 +693,15 @@ From:[(assert false (+ \"false \" \"should \" \"have \" \"been \" \"true\"))]" m (function _testWhenLetGuards [] // Guards should be allowed in whenLet patterns (whenLet [(when true 5) 5] - (Assert.pass))) \ No newline at end of file + (Assert.pass))) + +(function _testImportAndUsingInBuildMacro [] + (assertThrowsAtCompileTime (import pack.Type)) + (assertThrowsAtCompileTime (importAs pack.Type Alias)) + (assertThrowsAtCompileTime (importAll pack)) + (assertThrowsAtCompileTime (using pack.Type)) + (Assert.pass)) + +(function _testPureKissClasses [] + (PureKissClass.test) + (Assert.pass)) \ No newline at end of file