Convert most withPosOf() usage

This commit is contained in:
2021-01-16 20:45:38 -07:00
parent 9cc9407db6
commit b5a098e587
2 changed files with 104 additions and 54 deletions

View File

@@ -342,6 +342,9 @@ class Helpers {
meta: (m:String, exp:ReaderExp) -> MetaExp(m, exp).withPosOf(posRef), meta: (m:String, exp:ReaderExp) -> MetaExp(m, exp).withPosOf(posRef),
field: (f:String, exp:ReaderExp) -> FieldExp(f, exp).withPosOf(posRef), field: (f:String, exp:ReaderExp) -> FieldExp(f, exp).withPosOf(posRef),
keyValue: (key:ReaderExp, value:ReaderExp) -> KeyValueExp(key, value).withPosOf(posRef), keyValue: (key:ReaderExp, value:ReaderExp) -> KeyValueExp(key, value).withPosOf(posRef),
opToDynamic: (operandExp:ReaderExp) -> CallExp(Symbol("kiss.Operand.toDynamic").withPosOf(posRef), [operandExp]).withPosOf(posRef),
opFromDynamic: (operandExp:ReaderExp) -> CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(posRef), [operandExp]).withPosOf(posRef),
begin: (exps:Array<ReaderExp>) -> CallExp(Symbol("begin").withPosOf(posRef), exps).withPosOf(posRef)
}; };
} }
} }

View File

@@ -35,23 +35,25 @@ class Macros {
macros["%"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> { macros["%"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(2, 2, '(% [divisor] [dividend])'); wholeExp.checkNumArgs(2, 2, '(% [divisor] [dividend])');
CallExp(Symbol("kiss.Operand.toDynamic").withPosOf(wholeExp), [ var b = wholeExp.expBuilder();
CallExp(Symbol("Prelude.mod").withPosOf(wholeExp), [ b.opToDynamic(
CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp), [exps[1]]).withPosOf(wholeExp), b.call(
CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp), [exps[0]]).withPosOf(wholeExp) b.symbol("Prelude.mod"), [
]).withPosOf(wholeExp) b.opFromDynamic(exps[1]),
]).withPosOf(wholeExp); b.opFromDynamic(exps[0])
]));
}; };
destructiveVersion("%", "%="); destructiveVersion("%", "%=");
macros["^"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> { macros["^"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(2, 2, '(^ [base] [exponent])'); wholeExp.checkNumArgs(2, 2, '(^ [base] [exponent])');
CallExp(Symbol("kiss.Operand.toDynamic").withPosOf(wholeExp), [ var b = wholeExp.expBuilder();
CallExp(Symbol("Prelude.pow").withPosOf(wholeExp), [ b.opToDynamic(
CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp), [exps[1]]).withPosOf(wholeExp), b.call(b.symbol("Prelude.pow"), [
CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp), [exps[0]]).withPosOf(wholeExp) b.opFromDynamic(exps[1]),
]).withPosOf(wholeExp) b.opFromDynamic(exps[0])
]).withPosOf(wholeExp); ]));
}; };
destructiveVersion("^", "^="); destructiveVersion("^", "^=");
@@ -80,56 +82,79 @@ class Macros {
// the (apply [func] [args]) macro keeps its own list of aliases for the math operators // the (apply [func] [args]) macro keeps its own list of aliases for the math operators
// that can't just be function aliases because they emulate &rest behavior // that can't just be function aliases because they emulate &rest behavior
var opAliases = [ var opAliases = [
"+" => "Prelude.add", "-" => "Prelude.subtract", "*" => "Prelude.multiply", "/" => "Prelude.divide", ">" => "Prelude.greaterThan", "+" => "Prelude.add",
">=" => "Prelude.greaterEqual", "<" => "Prelude.lessThan", "<=" => "Prelude.lesserEqual", "=" => "Prelude.areEqual", "max" => "Prelude.max", "-" => "Prelude.subtract",
"*" => "Prelude.multiply",
"/" => "Prelude.divide",
">" => "Prelude.greaterThan",
">=" => "Prelude.greaterEqual",
"<" => "Prelude.lessThan",
"<=" => "Prelude.lesserEqual",
"=" => "Prelude.areEqual",
"max" => "Prelude.max",
"min" => "Prelude.min" "min" => "Prelude.min"
]; ];
macros["apply"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> { macros["apply"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(2, 2, '(apply [func] [argList])'); wholeExp.checkNumArgs(2, 2, '(apply [func] [argList])');
var b = wholeExp.expBuilder();
var callOn = switch (exps[0].def) { var callOn = switch (exps[0].def) {
case FieldExp(field, exp): case FieldExp(field, exp):
exp; exp;
default: default:
Symbol("null").withPosOf(wholeExp); b.symbol("null");
}; };
var func = switch (exps[0].def) { var func = switch (exps[0].def) {
case Symbol(sym) if (opAliases.exists(sym)): case Symbol(sym) if (opAliases.exists(sym)):
Symbol(opAliases[sym]).withPosOf(wholeExp); b.symbol(opAliases[sym]);
default: default:
exps[0]; exps[0];
}; };
var args = switch (exps[0].def) { var args = switch (exps[0].def) {
case Symbol(sym) if (opAliases.exists(sym)): case Symbol(sym) if (opAliases.exists(sym)):
ListExp([ b.list([
CallExp(FieldExp("map", exps[1]).withPosOf(wholeExp), [Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp)]).withPosOf(wholeExp) b.call(
]).withPosOf(wholeExp); b.field("map", exps[1]), [
b.symbol("kiss.Operand.fromDynamic")
])
]);
default: default:
exps[1]; exps[1];
}; };
CallExp(Symbol("Reflect.callMethod").withPosOf(wholeExp), [callOn, func, args]).withPosOf(wholeExp); b.call(
b.symbol("Reflect.callMethod"), [
callOn, func, args
]);
}; };
macros["range"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> { macros["range"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(1, 3, '(range [?min] [max] [?step])'); wholeExp.checkNumArgs(1, 3, '(range [?min] [max] [?step])');
var min = if (exps.length > 1) exps[0] else Symbol("0").withPosOf(wholeExp); var b = wholeExp.expBuilder();
var min = if (exps.length > 1) exps[0] else b.symbol("0");
var max = if (exps.length > 1) exps[1] else exps[0]; var max = if (exps.length > 1) exps[1] else exps[0];
var step = if (exps.length > 2) exps[2] else Symbol("1").withPosOf(wholeExp); var step = if (exps.length > 2) exps[2] else b.symbol("1");
CallExp(Symbol("Prelude.range").withPosOf(wholeExp), [min, max, step]).withPosOf(wholeExp); b.call(
b.symbol("Prelude.range"), [
min, max, step
]);
}; };
function bodyIf(formName:String, negated:Bool, wholeExp:ReaderExp, args:Array<ReaderExp>, k) { function bodyIf(formName:String, negated:Bool, wholeExp:ReaderExp, args:Array<ReaderExp>, k) {
wholeExp.checkNumArgs(2, null, '($formName [condition] [body...])'); wholeExp.checkNumArgs(2, null, '($formName [condition] [body...])');
var b = wholeExp.expBuilder();
var condition = if (negated) { var condition = if (negated) {
CallExp(Symbol("not").withPosOf(args[0]), [args[0]]).withPosOf(args[0]); b.call(
b.symbol("not"), [
args[0]
]);
} else { } else {
args[0]; args[0];
} }
return CallExp(Symbol("if").withPosOf(wholeExp), [ return b.call(b.symbol("if"), [
condition, condition,
CallExp(Symbol("begin").withPosOf(wholeExp), args.slice(1)).withPosOf(wholeExp) b.begin(args.slice(1))
]).withPosOf(wholeExp); ]);
} }
macros["when"] = bodyIf.bind("when", false); macros["when"] = bodyIf.bind("when", false);
macros["unless"] = bodyIf.bind("unless", true); macros["unless"] = bodyIf.bind("unless", true);
@@ -139,52 +164,69 @@ class Macros {
// (or... ) uses (cond... ) under the hood // (or... ) uses (cond... ) under the hood
macros["or"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k) -> { macros["or"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(2, null, "(or [v1] [v2] [values...])"); wholeExp.checkNumArgs(2, null, "(or [v1] [v2] [values...])");
var b = wholeExp.expBuilder();
var uniqueVarName = "_" + Uuid.v4().toShort(); var uniqueVarName = "_" + Uuid.v4().toShort();
var uniqueVarSymbol = Symbol(uniqueVarName).withPos(args[0].pos); var uniqueVarSymbol = b.symbol(uniqueVarName);
CallExp(Symbol("begin").withPosOf(wholeExp), [ b.begin([
CallExp(Symbol("deflocal").withPosOf(wholeExp), [ b.call(b.symbol("deflocal"), [
MetaExp("mut", TypedExp("Dynamic", uniqueVarSymbol).withPosOf(wholeExp)).withPosOf(wholeExp), b.meta("mut", b.typed("Dynamic", uniqueVarSymbol)),
Symbol("null").withPosOf(wholeExp) b.symbol("null")
]).withPos(args[0].pos), ]),
CallExp(Symbol("cond").withPosOf(wholeExp), [ b.call(b.symbol("cond"), [
for (arg in args) { for (arg in args) {
CallExp(CallExp(Symbol("set").withPosOf(wholeExp), [uniqueVarSymbol, arg]).withPosOf(wholeExp), [uniqueVarSymbol]).withPosOf(wholeExp); b.call(
b.call(b.symbol("set"), [
uniqueVarSymbol,
arg
]), [
uniqueVarSymbol
]);
} }
]).withPosOf(wholeExp) ])
]).withPosOf(wholeExp); ]);
}; };
// (and... uses (cond... ) and (not ...) under the hood) // (and... uses (cond... ) and (not ...) under the hood)
macros["and"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k) -> { macros["and"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k) -> {
wholeExp.checkNumArgs(2, null, "(and [v1] [v2] [values...])"); wholeExp.checkNumArgs(2, null, "(and [v1] [v2] [values...])");
var b = wholeExp.expBuilder();
var uniqueVarName = "_" + Uuid.v4().toShort(); var uniqueVarName = "_" + Uuid.v4().toShort();
var uniqueVarSymbol = Symbol(uniqueVarName).withPosOf(wholeExp); var uniqueVarSymbol = b.symbol(uniqueVarName);
var condCases = [ var condCases = [
for (arg in args) { for (arg in args) {
CallExp(CallExp(Symbol("not").withPosOf(wholeExp), b.call(
[ b.call(
CallExp(Symbol("set").withPosOf(wholeExp), [uniqueVarSymbol, arg]).withPosOf(wholeExp) b.symbol("not"), [
]).withPosOf(wholeExp), [Symbol("null").withPosOf(wholeExp)]).withPosOf(wholeExp); b.call(
b.symbol("set"), [uniqueVarSymbol, arg])
]), [
b.symbol("null")
]);
} }
]; ];
condCases.push(CallExp(Symbol("true").withPosOf(wholeExp), [uniqueVarSymbol]).withPosOf(wholeExp)); condCases.push(b.call(b.symbol("true"), [uniqueVarSymbol]));
CallExp(Symbol("begin").withPosOf(wholeExp), [ b.begin([
CallExp(Symbol("deflocal").withPosOf(wholeExp), [ b.call(
MetaExp("mut", TypedExp("Dynamic", uniqueVarSymbol).withPosOf(wholeExp)).withPosOf(wholeExp), b.symbol("deflocal"), [
Symbol("null").withPosOf(wholeExp) b.meta("mut", b.typed("Dynamic", uniqueVarSymbol)),
]).withPosOf(wholeExp), b.symbol("null")
CallExp(Symbol("cond").withPosOf(wholeExp), condCases).withPosOf(wholeExp) ]),
]).withPosOf(wholeExp); b.call(
b.symbol("cond"),
condCases)
]);
}; };
function arraySet(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) { function arraySet(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) {
return CallExp(Symbol("set").withPosOf(wholeExp), [ var b = wholeExp.expBuilder();
CallExp(Symbol("nth").withPosOf(wholeExp), [exps[0], exps[1]]).withPosOf(wholeExp), return b.call(
exps[2] b.symbol("set"), [
]).withPosOf(wholeExp); b.call(b.symbol("nth"), [exps[0], exps[1]]),
exps[2]
]);
} }
macros["setNth"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> { macros["setNth"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(3, 3, "(setNth [list] [index] [value])"); wholeExp.checkNumArgs(3, 3, "(setNth [list] [index] [value])");
@@ -195,6 +237,7 @@ class Macros {
arraySet(wholeExp, exps, k); arraySet(wholeExp, exps, k);
}; };
// TODO use expBuilder()
macros["assert"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> { macros["assert"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(1, 2, "(assert [expression] [message])"); wholeExp.checkNumArgs(1, 2, "(assert [expression] [message])");
var expression = exps[0]; var expression = exps[0];
@@ -378,8 +421,10 @@ class Macros {
// TODO macros for ifLet, whenLet (for assign then truthy check), caseLet (for extracting from enums) // TODO macros for ifLet, whenLet (for assign then truthy check), caseLet (for extracting from enums)
// TODO use expBuilder()
function awaitLet(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) { function awaitLet(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) {
wholeExp.checkNumArgs(2, null, "(awaitLet [[promise bindings...]] [body...])"); wholeExp.checkNumArgs(2, null, "(awaitLet [[promise bindings...]] [body...])");
// TODO make a dry bindingList extractor function
var bindingList = switch (exps[0].def) { var bindingList = switch (exps[0].def) {
case ListExp(bindingExps) if (bindingExps.length > 0 && bindingExps.length % 2 == 0): case ListExp(bindingExps) if (bindingExps.length > 0 && bindingExps.length % 2 == 0):
bindingExps; bindingExps;
@@ -414,6 +459,7 @@ class Macros {
return macros; return macros;
} }
// TODO use expBuilder()
// cond expands telescopically into a nested if expression // cond expands telescopically into a nested if expression
static function cond(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) { static function cond(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) {
wholeExp.checkNumArgs(1, null, "(cond [cases...])"); wholeExp.checkNumArgs(1, null, "(cond [cases...])");
@@ -433,6 +479,7 @@ class Macros {
}; };
} }
// TODO use expBuilder()
static function variadicMacro(func:String):MacroFunction { static function variadicMacro(func:String):MacroFunction {
return (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> { return (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
CallExp(Symbol(func).withPosOf(wholeExp), [ CallExp(Symbol(func).withPosOf(wholeExp), [