Always return macro expansions as ReaderExp with pos
This commit is contained in:
@@ -10,6 +10,7 @@ import kiss.ReaderExp;
|
|||||||
import kiss.CompileError;
|
import kiss.CompileError;
|
||||||
import kiss.Kiss;
|
import kiss.Kiss;
|
||||||
import kiss.SpecialForms;
|
import kiss.SpecialForms;
|
||||||
|
import kiss.Prelude;
|
||||||
import uuid.Uuid;
|
import uuid.Uuid;
|
||||||
|
|
||||||
using uuid.Uuid;
|
using uuid.Uuid;
|
||||||
@@ -234,14 +235,14 @@ class Helpers {
|
|||||||
// When we ARE running at compiletime already, the pre-existing interp will be used
|
// When we ARE running at compiletime already, the pre-existing interp will be used
|
||||||
static var interps:kiss.List<Interp> = [];
|
static var interps:kiss.List<Interp> = [];
|
||||||
|
|
||||||
public static function runAtCompileTime(exp:ReaderExp, k:KissState, ?args:Map<String, Dynamic>):Dynamic {
|
public static function runAtCompileTime(exp:ReaderExp, k:KissState, ?args:Map<String, Dynamic>):ReaderExp {
|
||||||
var code = k.convert(exp).toString(); // tink_macro to the rescue
|
var code = k.forHScript().convert(exp).toString(); // tink_macro to the rescue
|
||||||
#if test
|
#if test
|
||||||
Prelude.print("Compile-time hscript: " + code);
|
Prelude.print("Compile-time hscript: " + code);
|
||||||
#end
|
#end
|
||||||
var parser = new Parser();
|
var parser = new Parser();
|
||||||
if (interps.length == 0) {
|
if (interps.length == 0) {
|
||||||
var interp = new Interp();
|
var interp = new KissInterp();
|
||||||
interp.variables.set("read", Reader.assertRead.bind(_, k));
|
interp.variables.set("read", Reader.assertRead.bind(_, k));
|
||||||
interp.variables.set("readExpArray", Reader.readExpArray.bind(_, _, k));
|
interp.variables.set("readExpArray", Reader.readExpArray.bind(_, _, k));
|
||||||
interp.variables.set("ReaderExp", ReaderExpDef);
|
interp.variables.set("ReaderExp", ReaderExpDef);
|
||||||
@@ -254,12 +255,8 @@ class Helpers {
|
|||||||
fromDynamic: Operand.fromDynamic
|
fromDynamic: Operand.fromDynamic
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
interp.variables.set("k", k.forCaseParsing());
|
interp.variables.set("k", k.forHScript());
|
||||||
interp.variables.set("Helpers", Helpers);
|
interp.variables.set("Helpers", Helpers);
|
||||||
interp.variables.set("Prelude", Prelude);
|
|
||||||
interp.variables.set("Lambda", Lambda);
|
|
||||||
interp.variables.set("Std", Std);
|
|
||||||
|
|
||||||
interps.push(interp);
|
interps.push(interp);
|
||||||
} else {
|
} else {
|
||||||
interps.push(interps[-1]);
|
interps.push(interps[-1]);
|
||||||
@@ -283,20 +280,25 @@ class Helpers {
|
|||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw CompileError.fromExp(exp, "compile-time evaluation returned null");
|
throw CompileError.fromExp(exp, "compile-time evaluation returned null");
|
||||||
}
|
}
|
||||||
|
var expResult = compileTimeValueToReaderExp(value, exp);
|
||||||
#if test
|
#if test
|
||||||
var msg = "Compile-time value: ";
|
Prelude.print('Compile-time value: ${Reader.toString(expResult.def)}');
|
||||||
msg += try {
|
|
||||||
Reader.toString(value.def);
|
|
||||||
} catch (err:haxe.Exception) {
|
|
||||||
try {
|
|
||||||
Reader.toString(value);
|
|
||||||
} catch (err:haxe.Exception) {
|
|
||||||
Std.string(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Prelude.print(msg);
|
|
||||||
#end
|
#end
|
||||||
return value;
|
return expResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The value could be either a ReaderExp, ReaderExpDef, Array of ReaderExp/ReaderExpDefs, or something else entirely,
|
||||||
|
// but it needs to be a ReaderExp for evalUnquotes()
|
||||||
|
static function compileTimeValueToReaderExp(e:Dynamic, source:ReaderExp):ReaderExp {
|
||||||
|
return if (Std.isOfType(e, Array)) {
|
||||||
|
var arr:Array<Dynamic> = e;
|
||||||
|
var listExps = arr.map(compileTimeValueToReaderExp.bind(_, source));
|
||||||
|
ListExp(listExps).withPosOf(source);
|
||||||
|
} else if (e.def == null) {
|
||||||
|
(e : ReaderExpDef).withPosOf(source);
|
||||||
|
} else {
|
||||||
|
(e : ReaderExp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static function evalUnquoteLists(l:Array<ReaderExp>, k:KissState, ?args:Map<String, Dynamic>):Array<ReaderExp> {
|
static function evalUnquoteLists(l:Array<ReaderExp>, k:KissState, ?args:Map<String, Dynamic>):Array<ReaderExp> {
|
||||||
@@ -360,7 +362,7 @@ class Helpers {
|
|||||||
|
|
||||||
public static function removeTypeAnnotations(exp:ReaderExp):ReaderExp {
|
public static function removeTypeAnnotations(exp:ReaderExp):ReaderExp {
|
||||||
var def = switch (exp.def) {
|
var def = switch (exp.def) {
|
||||||
case Symbol(_) | StrExp(_) | RawHaxe(_):
|
case Symbol(_) | StrExp(_) | RawHaxe(_) | Quasiquote(_):
|
||||||
exp.def;
|
exp.def;
|
||||||
case CallExp(func, callArgs):
|
case CallExp(func, callArgs):
|
||||||
CallExp(removeTypeAnnotations(func), callArgs.map(removeTypeAnnotations));
|
CallExp(removeTypeAnnotations(func), callArgs.map(removeTypeAnnotations));
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ class Kiss {
|
|||||||
convert(elementExp);
|
convert(elementExp);
|
||||||
}
|
}
|
||||||
]).withMacroPosOf(exp);
|
]).withMacroPosOf(exp);
|
||||||
if (!isMap && k.wrapListExps) {
|
if (!isMap && k.wrapListExps && !k.hscript) {
|
||||||
ENew({
|
ENew({
|
||||||
pack: ["kiss"],
|
pack: ["kiss"],
|
||||||
name: "List"
|
name: "List"
|
||||||
@@ -231,9 +231,23 @@ class Kiss {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function forCaseParsing(k:KissState):KissState {
|
// Return an identical Kiss State, but without type annotations or wrapping list expressions as kiss.List constructor calls.
|
||||||
|
public static function forHScript(k:KissState):KissState {
|
||||||
|
var copy = new Cloner().clone(k);
|
||||||
|
copy.hscript = true;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an identical Kiss State, but without wrapping list expressions as kiss.List constructor calls.
|
||||||
|
public static function withoutListWrapping(k:KissState) {
|
||||||
var copy = new Cloner().clone(k);
|
var copy = new Cloner().clone(k);
|
||||||
copy.wrapListExps = false;
|
copy.wrapListExps = false;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an identical Kiss State, but prepared for parsing a branch pattern of a (case...) expression
|
||||||
|
public static function forCaseParsing(k:KissState):KissState {
|
||||||
|
var copy = withoutListWrapping(k);
|
||||||
copy.macros.remove("or");
|
copy.macros.remove("or");
|
||||||
copy.specialForms["or"] = SpecialForms.caseOr;
|
copy.specialForms["or"] = SpecialForms.caseOr;
|
||||||
return copy;
|
return copy;
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
package kiss;
|
package kiss;
|
||||||
|
|
||||||
import hscript.Interp;
|
import hscript.Interp;
|
||||||
|
import kiss.Prelude;
|
||||||
|
|
||||||
class KissInterp extends Interp {
|
class KissInterp extends Interp {
|
||||||
// TODO standardize this with KissConfig.prepareInterp
|
// TODO standardize this with KissConfig.prepareInterp
|
||||||
function new() {
|
public function new() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
variables.set("Prelude", Prelude);
|
variables.set("Prelude", Prelude);
|
||||||
variables.set("Lambda", Lambda);
|
variables.set("Lambda", Lambda);
|
||||||
variables.set("Std", Std);
|
variables.set("Std", Std);
|
||||||
|
variables.set("Keep", ExtraElementHandling.Keep);
|
||||||
|
variables.set("Drop", ExtraElementHandling.Drop);
|
||||||
|
variables.set("Throw", ExtraElementHandling.Throw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the default exprReturn() contains a try-catch which hides very important callstacks sometimes
|
||||||
|
override function exprReturn(e):Dynamic {
|
||||||
|
return expr(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,8 +365,7 @@ class Macros {
|
|||||||
args[innerArgNames.shift()] = innerExps.slice(restIndex);
|
args[innerArgNames.shift()] = innerExps.slice(restIndex);
|
||||||
|
|
||||||
// Return the macro expansion:
|
// Return the macro expansion:
|
||||||
var expDef:ReaderExpDef = Helpers.runAtCompileTime(CallExp(Symbol("begin").withPosOf(wholeExp), exps.slice(2)).withPosOf(wholeExp), k, args);
|
return Helpers.runAtCompileTime(CallExp(Symbol("begin").withPosOf(wholeExp), exps.slice(2)).withPosOf(wholeExp), k, args);
|
||||||
expDef.withPosOf(wholeExp);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
null;
|
null;
|
||||||
@@ -396,7 +395,7 @@ class Macros {
|
|||||||
stream.putBackString(s);
|
stream.putBackString(s);
|
||||||
}
|
}
|
||||||
var body = CallExp(Symbol("begin").withPos(stream.position()), exps.slice(2)).withPos(stream.position());
|
var body = CallExp(Symbol("begin").withPos(stream.position()), exps.slice(2)).withPos(stream.position());
|
||||||
Helpers.runAtCompileTime(body, k, [streamArgName => stream]);
|
Helpers.runAtCompileTime(body, k, [streamArgName => stream]).def;
|
||||||
};
|
};
|
||||||
case CallExp(_, []):
|
case CallExp(_, []):
|
||||||
throw CompileError.fromExp(exps[1], 'expected an argument list. Change the parens () to brackets []');
|
throw CompileError.fromExp(exps[1], 'expected an argument list. Change the parens () to brackets []');
|
||||||
|
|||||||
Reference in New Issue
Block a user