Refactor variadic handling so (apply [operator] [args]) will be possible
This commit is contained in:
@@ -20,13 +20,13 @@ class Macros {
|
||||
public static function builtins() {
|
||||
var macros:Map<String, MacroFunction> = [];
|
||||
|
||||
macros["+"] = foldMacro("Prelude.add");
|
||||
macros["+"] = variadicMacro("Prelude.add");
|
||||
|
||||
macros["-"] = foldMacro("Prelude.subtract");
|
||||
macros["-"] = variadicMacro("Prelude.subtract");
|
||||
|
||||
macros["*"] = foldMacro("Prelude.multiply");
|
||||
macros["*"] = variadicMacro("Prelude.multiply");
|
||||
|
||||
macros["/"] = foldMacro("Prelude.divide");
|
||||
macros["/"] = variadicMacro("Prelude.divide");
|
||||
|
||||
macros["%"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
|
||||
wholeExp.checkNumArgs(2, 2, '(% [divisor] [dividend])');
|
||||
@@ -38,15 +38,15 @@ class Macros {
|
||||
CallExp(Symbol("Prelude.pow").withPosOf(wholeExp), [exps[1], exps[0]]).withPosOf(wholeExp);
|
||||
};
|
||||
|
||||
macros["min"] = foldMacro("Prelude.min");
|
||||
macros["max"] = foldMacro("Prelude.max");
|
||||
macros["min"] = variadicMacro("Prelude.min");
|
||||
macros["max"] = variadicMacro("Prelude.max");
|
||||
|
||||
macros["_greaterThan"] = foldMacro("Prelude.greaterThan");
|
||||
macros["_greaterEqual"] = foldMacro("Prelude.greaterEqual");
|
||||
macros["_lessThan"] = foldMacro("Prelude.lessThan");
|
||||
macros["_lesserEqual"] = foldMacro("Prelude.lesserEqual");
|
||||
macros[">"] = variadicMacro("Prelude.greaterThan");
|
||||
macros[">="] = variadicMacro("Prelude.greaterEqual");
|
||||
macros["<"] = variadicMacro("Prelude.lessThan");
|
||||
macros["<="] = variadicMacro("Prelude.lesserEqual");
|
||||
|
||||
macros["_eq"] = foldMacro("Prelude.areEqual");
|
||||
macros["="] = variadicMacro("Prelude.areEqual");
|
||||
|
||||
function bodyIf(formName:String, negated:Bool, wholeExp:ReaderExp, args:Array<ReaderExp>, k) {
|
||||
wholeExp.checkNumArgs(2, null, '($formName [condition] [body...])');
|
||||
@@ -246,33 +246,14 @@ class Macros {
|
||||
};
|
||||
}
|
||||
|
||||
static function foldMacro(func:String):MacroFunction {
|
||||
static function variadicMacro(func:String):MacroFunction {
|
||||
return (wholeExp:ReaderExp, exps:Array<ReaderExp>, k) -> {
|
||||
// Lambda.fold calls need at least 1 argument
|
||||
wholeExp.checkNumArgs(1, null);
|
||||
|
||||
var uniqueVarExps = [];
|
||||
var bindingList = [];
|
||||
|
||||
for (exp in exps) {
|
||||
var uniqueVarName = "_" + Uuid.v4().toShort();
|
||||
var uniqueVarSymbol = Symbol(uniqueVarName).withPosOf(wholeExp);
|
||||
uniqueVarExps.push(uniqueVarSymbol);
|
||||
bindingList = bindingList.concat([
|
||||
TypedExp("kiss.Operand", uniqueVarSymbol).withPosOf(wholeExp),
|
||||
CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp), [exp]).withPosOf(wholeExp)
|
||||
]);
|
||||
};
|
||||
|
||||
CallExp(Symbol("let").withPosOf(wholeExp), [
|
||||
ListExp(bindingList).withPosOf(wholeExp),
|
||||
CallExp(Symbol("kiss.Operand.toDynamic").withPosOf(wholeExp), [
|
||||
CallExp(Symbol("Lambda.fold").withPosOf(wholeExp), [
|
||||
ListExp(uniqueVarExps.slice(1)).withPosOf(wholeExp),
|
||||
Symbol(func).withPosOf(wholeExp),
|
||||
uniqueVarExps[0]
|
||||
]).withPosOf(wholeExp)
|
||||
]).withPosOf(wholeExp),
|
||||
CallExp(Symbol(func).withPosOf(wholeExp), [
|
||||
ListExp([
|
||||
for (exp in exps) {
|
||||
CallExp(Symbol("kiss.Operand.fromDynamic").withPosOf(wholeExp), [exp]).withPosOf(wholeExp);
|
||||
}
|
||||
]).withPosOf(wholeExp)
|
||||
]).withPosOf(wholeExp);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,8 +6,19 @@ import kiss.Operand;
|
||||
import haxe.ds.Either;
|
||||
|
||||
class Prelude {
|
||||
static function variadic(op:(Operand, Operand) -> Null<Operand>, comparison = false):(Array<Operand>) -> Dynamic {
|
||||
return (l:kiss.List<Operand>) -> switch (Lambda.fold(l.slice(1), op, l[0])) {
|
||||
case null:
|
||||
false;
|
||||
case somethingElse if (comparison):
|
||||
true;
|
||||
case somethingElse:
|
||||
Operand.toDynamic(somethingElse);
|
||||
};
|
||||
}
|
||||
|
||||
// Kiss arithmetic will incur overhead because of these switch statements, but the results will not be platform-dependent
|
||||
public static function add(a:Operand, b:Operand):Operand {
|
||||
static function _add(a:Operand, b:Operand):Operand {
|
||||
return switch ([a, b]) {
|
||||
case [Left(str), Left(str2)]:
|
||||
Left(str2 + str);
|
||||
@@ -18,7 +29,9 @@ class Prelude {
|
||||
};
|
||||
}
|
||||
|
||||
public static function subtract(val:Operand, from:Operand):Operand {
|
||||
public static var add = variadic(_add);
|
||||
|
||||
static function _subtract(val:Operand, from:Operand):Operand {
|
||||
return switch ([from, val]) {
|
||||
case [Right(from), Right(val)]:
|
||||
Right(from - val);
|
||||
@@ -27,7 +40,9 @@ class Prelude {
|
||||
}
|
||||
}
|
||||
|
||||
public static function multiply(a:Operand, b:Operand):Operand {
|
||||
public static var subtract = variadic(_subtract);
|
||||
|
||||
static function _multiply(a:Operand, b:Operand):Operand {
|
||||
return switch ([a, b]) {
|
||||
case [Right(f), Right(f2)]:
|
||||
Right(f * f2);
|
||||
@@ -44,7 +59,9 @@ class Prelude {
|
||||
};
|
||||
}
|
||||
|
||||
public static function divide(bottom:Operand, top:Operand):Operand {
|
||||
public static var multiply = variadic(_multiply);
|
||||
|
||||
static function _divide(bottom:Operand, top:Operand):Operand {
|
||||
return switch ([top, bottom]) {
|
||||
case [Right(f), Right(f2)]:
|
||||
Right(f / f2);
|
||||
@@ -53,6 +70,8 @@ class Prelude {
|
||||
};
|
||||
}
|
||||
|
||||
public static var divide = variadic(_divide);
|
||||
|
||||
public static function mod(bottom:Float, top:Float):Float {
|
||||
return top % bottom;
|
||||
}
|
||||
@@ -61,34 +80,48 @@ class Prelude {
|
||||
return Math.pow(base, exponent);
|
||||
}
|
||||
|
||||
public static function min(a:Operand, b:Operand):Operand {
|
||||
static function _min(a:Operand, b:Operand):Operand {
|
||||
return Right(Math.min(a.toFloat(), b.toFloat()));
|
||||
}
|
||||
|
||||
public static function max(a:Operand, b:Operand):Operand {
|
||||
public static var min = variadic(_min);
|
||||
|
||||
static function _max(a:Operand, b:Operand):Operand {
|
||||
return Right(Math.max(a.toFloat(), b.toFloat()));
|
||||
}
|
||||
|
||||
public static function greaterThan(b:Operand, a:Operand):Null<Operand> {
|
||||
public static var max = variadic(_max);
|
||||
|
||||
static function _greaterThan(b:Operand, a:Operand):Null<Operand> {
|
||||
return if (a == null || b == null) null else if (a.toFloat() > b.toFloat()) b else null;
|
||||
}
|
||||
|
||||
public static function greaterEqual(b:Operand, a:Operand):Null<Operand> {
|
||||
public static var greaterThan = variadic(_greaterThan, true);
|
||||
|
||||
static function _greaterEqual(b:Operand, a:Operand):Null<Operand> {
|
||||
return if (a == null || b == null) null else if (a.toFloat() >= b.toFloat()) b else null;
|
||||
}
|
||||
|
||||
public static function lessThan(b:Operand, a:Operand):Null<Operand> {
|
||||
public static var greaterEqual = variadic(_greaterEqual, true);
|
||||
|
||||
static function _lessThan(b:Operand, a:Operand):Null<Operand> {
|
||||
return if (a == null || b == null) null else if (a.toFloat() < b.toFloat()) b else null;
|
||||
}
|
||||
|
||||
public static function lesserEqual(b:Operand, a:Operand):Null<Operand> {
|
||||
public static var lessThan = variadic(_lessThan, true);
|
||||
|
||||
static function _lesserEqual(b:Operand, a:Operand):Null<Operand> {
|
||||
return if (a == null || b == null) null else if (a.toFloat() <= b.toFloat()) b else null;
|
||||
}
|
||||
|
||||
public static function areEqual(a:Operand, b:Operand):Operand {
|
||||
public static var lesserEqual = variadic(_lesserEqual, true);
|
||||
|
||||
static function _areEqual(a:Operand, b:Operand):Operand {
|
||||
return if (Operand.toDynamic(a) == Operand.toDynamic(b)) a else null;
|
||||
}
|
||||
|
||||
public static var areEqual = variadic(_areEqual, true);
|
||||
|
||||
public static function groups<T>(a:Array<T>, size, keepRemainder = false) {
|
||||
var numFullGroups = Math.floor(a.length / size);
|
||||
var fullGroups = [
|
||||
|
||||
@@ -247,12 +247,6 @@ class SpecialForms {
|
||||
EThrow(k.convert(args[0])).withMacroPosOf(wholeExp);
|
||||
};
|
||||
|
||||
map[">"] = foldComparison("_greaterThan");
|
||||
map[">="] = foldComparison("_greaterEqual");
|
||||
map["<"] = foldComparison("_lessThan");
|
||||
map["<="] = foldComparison("_lesserEqual");
|
||||
map["="] = foldComparison("_eq");
|
||||
|
||||
map["if"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
|
||||
wholeExp.checkNumArgs(2, 3, '(if [cond] [then] [?else])');
|
||||
|
||||
@@ -282,12 +276,4 @@ class SpecialForms {
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static function foldComparison(func:String) {
|
||||
return (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
|
||||
var callFoldMacroExpr = k.convert(CallExp(Symbol(func).withPosOf(wholeExp), args).withPosOf(wholeExp));
|
||||
wholeExp.checkNumArgs(1, null);
|
||||
EBinop(OpNotEq, macro null, macro kiss.Operand.toDynamic($callFoldMacroExpr)).withMacroPosOf(wholeExp);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
|
||||
(defun _testMultiplication []
|
||||
(Assert.equals 60 (* 2 5 6))
|
||||
(Assert.equals 5522401584 (* 84 289 89 71 36)))
|
||||
(Assert.equals 5522401584 (* 84 289 89 71 36))
|
||||
(Assert.equals "heyheyhey" (* "hey" 3)))
|
||||
|
||||
// All math operations return floats, none truncate by default
|
||||
(defvar myQuotient (/ 6 3 2 2))
|
||||
|
||||
Reference in New Issue
Block a user