throwCompileError in expBuilder
This commit is contained in:
@@ -19,6 +19,15 @@ class CompileError {
|
|||||||
return new CompileError([exp], message);
|
return new CompileError([exp], message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromExpStr(pos:Position, expStr:String, message:String) {
|
||||||
|
switch (Reader.read(Stream.fromString(expStr), Kiss.defaultKissState())) {
|
||||||
|
case Some(exp):
|
||||||
|
return fromExp({pos: pos, def: exp.def}, message);
|
||||||
|
default:
|
||||||
|
throw 'bad'; // TODO better message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function fromArgs(exps:Array<ReaderExp>, message:String) {
|
public static function fromArgs(exps:Array<ReaderExp>, message:String) {
|
||||||
return new CompileError(exps, message);
|
return new CompileError(exps, message);
|
||||||
}
|
}
|
||||||
|
@@ -558,6 +558,21 @@ class Helpers {
|
|||||||
function list(exps:Array<ReaderExp>) {
|
function list(exps:Array<ReaderExp>) {
|
||||||
return ListExp(exps).withPosOf(posRef);
|
return ListExp(exps).withPosOf(posRef);
|
||||||
}
|
}
|
||||||
|
function objectWith (bindings:Array<ReaderExp>, captures:Array<ReaderExp>) {
|
||||||
|
return callSymbol("objectWith", [list(bindings)].concat(captures));
|
||||||
|
}
|
||||||
|
function str(s:String) {
|
||||||
|
return StrExp(s).withPosOf(posRef);
|
||||||
|
}
|
||||||
|
function raw(code:String) {
|
||||||
|
return RawHaxe(code).withPosOf(posRef);
|
||||||
|
}
|
||||||
|
function int(v:Int) {
|
||||||
|
return _symbol(Std.string(v));
|
||||||
|
}
|
||||||
|
function float(v:Float) {
|
||||||
|
return _symbol(Std.string(v));
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
call: call,
|
call: call,
|
||||||
callSymbol: callSymbol,
|
callSymbol: callSymbol,
|
||||||
@@ -565,15 +580,34 @@ class Helpers {
|
|||||||
print: (arg:ReaderExp) -> CallExp(Symbol("print").withPosOf(posRef), [arg]).withPosOf(posRef),
|
print: (arg:ReaderExp) -> CallExp(Symbol("print").withPosOf(posRef), [arg]).withPosOf(posRef),
|
||||||
the: (type:ReaderExp, value:ReaderExp) -> callSymbol("the", [type, value]),
|
the: (type:ReaderExp, value:ReaderExp) -> callSymbol("the", [type, value]),
|
||||||
list: list,
|
list: list,
|
||||||
str: (s:String) -> StrExp(s).withPosOf(posRef),
|
str: str,
|
||||||
symbol: _symbol,
|
symbol: _symbol,
|
||||||
raw: (code:String) -> RawHaxe(code).withPosOf(posRef),
|
int: int,
|
||||||
|
float: float,
|
||||||
|
raw: raw,
|
||||||
typed: (path:String, exp:ReaderExp) -> TypedExp(path, exp).withPosOf(posRef),
|
typed: (path:String, exp:ReaderExp) -> TypedExp(path, exp).withPosOf(posRef),
|
||||||
meta: (m:String, exp:ReaderExp) -> MetaExp(m, exp).withPosOf(posRef),
|
meta: (m:String, exp:ReaderExp) -> MetaExp(m, exp).withPosOf(posRef),
|
||||||
field: field,
|
field: field,
|
||||||
keyValue: (key:ReaderExp, value:ReaderExp) -> KeyValueExp(key, value).withPosOf(posRef),
|
keyValue: (key:ReaderExp, value:ReaderExp) -> KeyValueExp(key, value).withPosOf(posRef),
|
||||||
begin: (exps:Array<ReaderExp>) -> callSymbol("begin", exps),
|
begin: (exps:Array<ReaderExp>) -> callSymbol("begin", exps),
|
||||||
let: (bindings:Array<ReaderExp>, body:Array<ReaderExp>) -> callSymbol("let", [list(bindings)].concat(body)),
|
let: (bindings:Array<ReaderExp>, body:Array<ReaderExp>) -> callSymbol("let", [list(bindings)].concat(body)),
|
||||||
|
objectWith: objectWith,
|
||||||
|
throwCompileError: (reason:String) -> {
|
||||||
|
callSymbol("throw", [
|
||||||
|
callSymbol("CompileError.fromExpStr", [
|
||||||
|
// pos
|
||||||
|
objectWith([
|
||||||
|
_symbol("file"), str(posRef.pos.file),
|
||||||
|
_symbol("line"), int(posRef.pos.line),
|
||||||
|
_symbol("column"), int(posRef.pos.column),
|
||||||
|
_symbol("absoluteChar"), int(posRef.pos.absoluteChar),
|
||||||
|
], []),
|
||||||
|
// expStr
|
||||||
|
str(Reader.toString(posRef.def)),
|
||||||
|
str(reason)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
},
|
||||||
none: () -> None.withPosOf(posRef)
|
none: () -> None.withPosOf(posRef)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -376,7 +376,8 @@ class Kiss {
|
|||||||
static function disableMacro(copy:KissState, m:String, reason:String) {
|
static function disableMacro(copy:KissState, m:String, reason:String) {
|
||||||
copy.macros[m] = (wholeExp:ReaderExp, exps, k) -> {
|
copy.macros[m] = (wholeExp:ReaderExp, exps, k) -> {
|
||||||
var b = wholeExp.expBuilder();
|
var b = wholeExp.expBuilder();
|
||||||
b.callSymbol("throw", [b.str('$m is unavailable in macros because $reason')]);
|
// have this throw during macroEXPANSION, not before (so assertThrows will catch it)
|
||||||
|
b.throwCompileError('$m is unavailable in macros because $reason');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,8 +400,18 @@ class Kiss {
|
|||||||
|
|
||||||
public static function forMacroEval(k:KissState): KissState {
|
public static function forMacroEval(k:KissState): KissState {
|
||||||
var copy = k.forHScript();
|
var copy = k.forHScript();
|
||||||
// Disable macros that will cause problems in macro evaluation:
|
// Catch accidental misuse of (set) on macroVars
|
||||||
disableMacro(copy, "set", "you don't want your macros to be stateful");
|
var setLocal = copy.specialForms["set"];
|
||||||
|
copy.specialForms["set"] = (wholeExp:ReaderExp, exps, k:KissState) -> {
|
||||||
|
switch (exps[0].def) {
|
||||||
|
case Symbol(varName) if (k.macroVars.exists(varName)):
|
||||||
|
var b = wholeExp.expBuilder();
|
||||||
|
// have this throw during macroEXPANSION, not before (so assertThrows will catch it)
|
||||||
|
copy.convert(b.throwCompileError('If you intend to change macroVar $varName, use defMacroVar instead. If not, rename your local variable for clarity.'));
|
||||||
|
default:
|
||||||
|
setLocal(wholeExp, exps, copy);
|
||||||
|
};
|
||||||
|
};
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,6 +44,10 @@ class KissInterp extends Interp {
|
|||||||
variables.set("Http", sys.Http);
|
variables.set("Http", sys.Http);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
variables.set("CompileError", kiss.CompileError);
|
||||||
|
#end
|
||||||
|
|
||||||
// Might eventually need to simulate types in the namespace:
|
// Might eventually need to simulate types in the namespace:
|
||||||
variables.set("kiss", {});
|
variables.set("kiss", {});
|
||||||
}
|
}
|
||||||
|
@@ -470,7 +470,9 @@ class Macros {
|
|||||||
try {
|
try {
|
||||||
// Return the macro expansion:
|
// Return the macro expansion:
|
||||||
return Helpers.runAtCompileTime(b.callSymbol("begin", exps.slice(2)), k, args);
|
return Helpers.runAtCompileTime(b.callSymbol("begin", exps.slice(2)), k, args);
|
||||||
} catch (error) {
|
} catch (error:CompileError) {
|
||||||
|
throw error;
|
||||||
|
} catch (error:Dynamic) {
|
||||||
throw CompileError.fromExp(wholeExp, 'Macro expansion error: $error');
|
throw CompileError.fromExp(wholeExp, 'Macro expansion error: $error');
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -46,6 +46,10 @@ class MacroTestCase extends Test {
|
|||||||
_testSetMacroVar();
|
_testSetMacroVar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testRedefineMacroVar() {
|
||||||
|
_testRedefineMacroVar();
|
||||||
|
}
|
||||||
|
|
||||||
function testTryCatchWithoutDynamic () {
|
function testTryCatchWithoutDynamic () {
|
||||||
_testTryCatchWithoutDynamic();
|
_testTryCatchWithoutDynamic();
|
||||||
}
|
}
|
||||||
|
@@ -60,6 +60,7 @@
|
|||||||
(_testPrintAtMacroTimeMacro)
|
(_testPrintAtMacroTimeMacro)
|
||||||
(Assert.pass))
|
(Assert.pass))
|
||||||
|
|
||||||
|
// Calling (set) on a macroVar is a faux-pas, but calling defMacroVar again is not
|
||||||
(defMacroVar count 0)
|
(defMacroVar count 0)
|
||||||
(defMacro _testSetMacroVarMacro []
|
(defMacro _testSetMacroVarMacro []
|
||||||
(assertThrows (set count (+ count 1)))
|
(assertThrows (set count (+ count 1)))
|
||||||
@@ -69,6 +70,15 @@
|
|||||||
(_testSetMacroVarMacro)
|
(_testSetMacroVarMacro)
|
||||||
(Assert.pass))
|
(Assert.pass))
|
||||||
|
|
||||||
|
(defMacro _testRedefineMacroVarMacro []
|
||||||
|
(defMacroVar count (+ count 1))
|
||||||
|
(symbol (Std.string count)))
|
||||||
|
|
||||||
|
(function _testRedefineMacroVar []
|
||||||
|
(Assert.equals 1 (_testRedefineMacroVarMacro))
|
||||||
|
(Assert.equals 2 (_testRedefineMacroVarMacro)))
|
||||||
|
|
||||||
|
|
||||||
// ifLet and its derivatives should be disabled in defMacro bodies:
|
// ifLet and its derivatives should be disabled in defMacro bodies:
|
||||||
(defMacro _testIfLetDisabledMacro []
|
(defMacro _testIfLetDisabledMacro []
|
||||||
(assertThrows (ifLet [a "b"] a))
|
(assertThrows (ifLet [a "b"] a))
|
||||||
|
Reference in New Issue
Block a user