add haxe @meta support to kiss expressions
This commit is contained in:
@@ -475,7 +475,7 @@ class Kiss {
|
||||
}
|
||||
|
||||
// Core functionality of Kiss: returns ReaderExp when macroExpandOnly is true, and haxe.macro.Expr otherwise
|
||||
public static function macroExpandAndConvert(exp:ReaderExp, k:KissState, macroExpandOnly:Bool):Either<ReaderExp,Expr> {
|
||||
public static function macroExpandAndConvert(exp:ReaderExp, k:KissState, macroExpandOnly:Bool, ?metaNames, ?metaParams:Array<Array<Expr>>, ?metaPos:Array<haxe.macro.Position>):Either<ReaderExp,Expr> {
|
||||
#if kissCache
|
||||
var str = Reader.toString(exp.def);
|
||||
if (!macroExpandOnly) {
|
||||
@@ -544,6 +544,21 @@ class Kiss {
|
||||
var expr:Either<ReaderExp,Expr> = switch (exp.def) {
|
||||
case None:
|
||||
if (macroExpandOnly) Left(exp) else Right(none);
|
||||
case HaxeMeta(name, params, exp):
|
||||
if (macroExpandOnly) {
|
||||
Left(HaxeMeta(name, params, left(macroExpandAndConvert(exp, k, true))).withPosOf(exp));
|
||||
} else {
|
||||
if (metaNames == null) metaNames = [];
|
||||
if (metaParams == null) metaParams = [];
|
||||
if (metaPos == null) metaPos = [];
|
||||
metaNames.push(name);
|
||||
if (params == null)
|
||||
metaParams.push(null);
|
||||
else
|
||||
metaParams.push([for (param in params) right(macroExpandAndConvert(param, k, false))]);
|
||||
metaPos.push(Helpers.macroPos(exp));
|
||||
Right(right(macroExpandAndConvert(exp, k, false, metaNames, metaParams, metaPos)));
|
||||
}
|
||||
case Symbol(alias) if (k.identAliases.exists(alias)):
|
||||
var substitution = k.identAliases[alias].withPosOf(exp);
|
||||
if (macroExpandOnly) Left(substitution) else macroExpandAndConvert(substitution, k, false);
|
||||
@@ -558,6 +573,16 @@ class Kiss {
|
||||
case CallExp({pos: _, def: Symbol(ff)}, args) if (fieldForms.exists(ff) && !macroExpandOnly):
|
||||
checkNumArgs(ff);
|
||||
var field = fieldForms[ff](exp, args.copy(), k);
|
||||
if (metaNames != null) {
|
||||
field.meta = [];
|
||||
while (metaNames.length > 0) {
|
||||
field.meta.push({
|
||||
name: metaNames.shift(),
|
||||
params: metaParams.shift(),
|
||||
pos: metaPos.shift()
|
||||
});
|
||||
}
|
||||
}
|
||||
k.fieldList.push(field);
|
||||
k.fieldDict[field.name] = field;
|
||||
k.stateChanged = true;
|
||||
@@ -665,6 +690,13 @@ class Kiss {
|
||||
}
|
||||
}
|
||||
#end
|
||||
if (metaNames != null && !macroExpandOnly) {
|
||||
expr = Right(EMeta({
|
||||
name: metaNames.pop(),
|
||||
params: metaParams.pop(),
|
||||
pos: metaPos.pop()
|
||||
}, right(expr)).withMacroPosOf(exp));
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
@@ -32,11 +32,16 @@ class Reader {
|
||||
var pos = stream.position();
|
||||
CallExp(assertRead(stream, k), readExpArray(stream, ")", k, pos));
|
||||
};
|
||||
|
||||
readTable["@"] = (stream, k) -> HaxeMeta(nextToken(stream, "a haxe metadata entry name"), null, assertRead(stream, k));
|
||||
readTable["@("] = (stream, k) -> HaxeMeta(nextToken(stream, "a haxe metadata entry name"), readExpArray(stream, ")", k), assertRead(stream, k));
|
||||
|
||||
readTable["["] = (stream, k) -> ListExp(readExpArray(stream, "]", k));
|
||||
readTable["[::"] = (stream, k) -> ListEatingExp(readExpArray(stream, "]", k));
|
||||
readTable["..."] = (stream, k) -> ListRestExp(nextToken(stream, "name for list-eating rest exp", true));
|
||||
// Provides a nice syntactic sugar for (if... {[then block]} {[else block]}),
|
||||
// and also handles string interpolation cases like "${exp}moreString"
|
||||
|
||||
// Provides a nice syntactic sugar for (if... {<then block...>} {<else block...>}),
|
||||
// and also handles string interpolation cases like "${exp}moreString":
|
||||
readTable["{"] = (stream:Stream, k) -> CallExp(Symbol("begin").withPos(stream.position()), readExpArray(stream, "}", k));
|
||||
|
||||
readTable["<>["] = (stream, k) -> TypeParams(readExpArray(stream, "]", k));
|
||||
@@ -567,6 +572,10 @@ class Reader {
|
||||
'...${name}';
|
||||
case None:
|
||||
'';
|
||||
case HaxeMeta(name, null, exp):
|
||||
'@${name} ${exp.def.toString()}';
|
||||
case HaxeMeta(name, params, exp):
|
||||
'@(${name} ${[for (param in params) param.def.toString()].join(" ")}) ${exp.def.toString()}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,5 +24,6 @@ enum ReaderExpDef {
|
||||
ListEatingExp(exps:Array<ReaderExp>); // [::exp exp ...exps exp]
|
||||
ListRestExp(name:String); // ...exps or ...
|
||||
TypeParams(types:Array<ReaderExp>); // <>[T :Constraint U :Constraint1 :Constraint2 V]
|
||||
HaxeMeta(name:String, params:Null<Array<ReaderExp>>, exp:ReaderExp); // @meta <exp> or @(meta <params...>) <exp>
|
||||
None; // not an expression, i.e. (#unless falseCondition exp)
|
||||
}
|
||||
|
Reference in New Issue
Block a user