\#if conditional compilation macro
This commit is contained in:
@@ -11,10 +11,14 @@ import kiss.Prelude;
|
||||
* macro definitions.
|
||||
*/
|
||||
class KissInterp extends Interp {
|
||||
var nullForUnknownVar:Bool;
|
||||
|
||||
// TODO standardize this with KissConfig.prepareInterp
|
||||
public function new() {
|
||||
public function new(nullForUnknownVar = false) {
|
||||
super();
|
||||
|
||||
this.nullForUnknownVar = nullForUnknownVar;
|
||||
|
||||
variables.set("Prelude", Prelude);
|
||||
variables.set("Lambda", Lambda);
|
||||
variables.set("Std", Std);
|
||||
@@ -23,6 +27,18 @@ class KissInterp extends Interp {
|
||||
variables.set("Throw", ExtraElementHandling.Throw);
|
||||
}
|
||||
|
||||
override function resolve(id:String):Dynamic {
|
||||
if (nullForUnknownVar) {
|
||||
return try {
|
||||
super.resolve(id);
|
||||
} catch (e:Dynamic) {
|
||||
null;
|
||||
}
|
||||
} else {
|
||||
return super.resolve(id);
|
||||
}
|
||||
}
|
||||
|
||||
override function exprReturn(e):Dynamic {
|
||||
// the default exprReturn() contains a try-catch which, though it is important, hides very important macroexpansion callstacks sometimes
|
||||
#if macrotest
|
||||
|
@@ -8,6 +8,7 @@ import kiss.Kiss;
|
||||
import kiss.CompileError;
|
||||
import uuid.Uuid;
|
||||
import sys.io.Process;
|
||||
import hscript.Parser;
|
||||
|
||||
using kiss.Kiss;
|
||||
using kiss.Reader;
|
||||
@@ -171,6 +172,32 @@ class Macros {
|
||||
]);
|
||||
};
|
||||
|
||||
// Conditional compilation is all based on this macro:
|
||||
macros["#if"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
|
||||
wholeExp.checkNumArgs(2, 3, '(#if [cond] [then] [?else])');
|
||||
|
||||
var conditionExp = exps.shift();
|
||||
var thenExp = exps.shift();
|
||||
var elseExp = if (exps.length > 0) exps.shift(); else null;
|
||||
|
||||
var parser = new Parser();
|
||||
var conditionInterp = new KissInterp(true);
|
||||
var conditionStr = Reader.toString(conditionExp.def);
|
||||
var conditionHScript = parser.parseString(Prelude.convertToHScript(conditionStr));
|
||||
for (flag => value in Context.getDefines()) {
|
||||
conditionInterp.variables.set(flag, value);
|
||||
}
|
||||
try {
|
||||
return if (Prelude.truthy(conditionInterp.execute(conditionHScript))) {
|
||||
thenExp;
|
||||
} else {
|
||||
elseExp;
|
||||
}
|
||||
} catch (e) {
|
||||
throw CompileError.fromExp(conditionExp, 'condition for #if threw error $e');
|
||||
}
|
||||
};
|
||||
|
||||
function bodyIf(formName:String, negated:Bool, wholeExp:ReaderExp, args:Array<ReaderExp>, k) {
|
||||
wholeExp.checkNumArgs(2, null, '($formName [condition] [body...])');
|
||||
var b = wholeExp.expBuilder();
|
||||
|
@@ -36,6 +36,16 @@ class Reader {
|
||||
readTable['"'] = readString;
|
||||
readTable["#"] = readRawString;
|
||||
|
||||
// Special symbols that wouldn't read as symbols, but should:
|
||||
function forceSymbol(sym:String) {
|
||||
readTable[sym] = (stream, k) -> Symbol(sym);
|
||||
}
|
||||
forceSymbol("#if");
|
||||
forceSymbol("#when");
|
||||
forceSymbol("#unless");
|
||||
forceSymbol("#cond");
|
||||
forceSymbol("#case");
|
||||
|
||||
readTable["/*"] = (stream, k) -> {
|
||||
stream.takeUntilAndDrop("*/");
|
||||
null;
|
||||
@@ -314,7 +324,7 @@ class Reader {
|
||||
case '"':
|
||||
break;
|
||||
default:
|
||||
stream.error('Invalid syntax for raw string. Delete $next');
|
||||
stream.error('Invalid syntax for raw string.');
|
||||
return null;
|
||||
}
|
||||
} while (true);
|
||||
|
20
kiss/src/test/cases/ConditionalCompilationTestCase.hx
Normal file
20
kiss/src/test/cases/ConditionalCompilationTestCase.hx
Normal file
@@ -0,0 +1,20 @@
|
||||
package test.cases;
|
||||
|
||||
import utest.Assert;
|
||||
import utest.Test;
|
||||
import kiss.Prelude;
|
||||
|
||||
@:build(kiss.Kiss.build())
|
||||
class ConditionalCompilationTestCase extends Test {
|
||||
function testIf() {
|
||||
#if interp
|
||||
Assert.isTrue(runningInHaxe);
|
||||
#else
|
||||
Assert.isFalse(runningInHaxe);
|
||||
#end
|
||||
|
||||
#if (py || js)
|
||||
Assert.isTrue(runningInPyOrJs);
|
||||
#end
|
||||
}
|
||||
}
|
3
kiss/src/test/cases/ConditionalCompilationTestCase.kiss
Normal file
3
kiss/src/test/cases/ConditionalCompilationTestCase.kiss
Normal file
@@ -0,0 +1,3 @@
|
||||
(defvar runningInHaxe (#if interp true false))
|
||||
(defvar runningInPyOrJs (#if (or py js) true false))
|
||||
|
Reference in New Issue
Block a user