(import) and (using) for pure-kiss classes

This commit is contained in:
2022-10-06 00:49:05 +00:00
parent 0040cfea11
commit 2f6431f8c2
7 changed files with 96 additions and 18 deletions

View File

@@ -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<Field> {
public static function build(?kissFile:String, ?k:KissState, useClassFields = true, ?context:FrontendContext):Array<Field> {
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();

View File

@@ -15,15 +15,18 @@ class KissFrontend implements FrontendPlugin {
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());
}

View File

@@ -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<ReaderExp>, k:KissState) -> Expr;
class SpecialForms {
public static function builtins(k:KissState) {
public static function builtins(k:KissState, ?context:FrontendContext) {
var map:Map<String, SpecialFormFunction> = [];
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 <types...>)");
map["import"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, 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 <Type> <Alias>)");
map["importAs"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, 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 <package>)");
map["importAll"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
requireContext(wholeExp, "importAll");
context.addImport(Reader.toString(exps[0].def), IAll, wholeExp.macroPos());
return none(wholeExp);
};
k.doc("using", 1, null, "(using <Types...>)");
map["using"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
requireContext(wholeExp, "using");
for (type in exps) {
context.addUsing(Reader.toString(type.def), wholeExp.macroPos());
}
return none(wholeExp);
};
return map;
}

View File

@@ -0,0 +1,3 @@
(function extensionMethod [:String s] "EXTENDED")
(defNew [&prop :Int num])

View File

@@ -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))))

View File

@@ -364,9 +364,17 @@ class BasicTestCase extends Test {
_testQuickFractions();
}
function testWhenLetGuards() {
function testWhenLetGuards() {
_testWhenLetGuards();
}
}
function testImportAndUsingInBuildMacro() {
_testImportAndUsingInBuildMacro();
}
function testPureKissClasses() {
_testPureKissClasses();
}
}

View File

@@ -694,3 +694,14 @@ From:[(assert false (+ \"false \" \"should \" \"have \" \"been \" \"true\"))]" m
// Guards should be allowed in whenLet patterns
(whenLet [(when true 5) 5]
(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))