diff --git a/src/kiss/FieldForms.hx b/src/kiss/FieldForms.hx index ee0f470f..76acb3f8 100644 --- a/src/kiss/FieldForms.hx +++ b/src/kiss/FieldForms.hx @@ -3,17 +3,17 @@ package kiss; import haxe.macro.Expr; import haxe.macro.Context; import kiss.Reader; -import kiss.Types; import kiss.Helpers; import kiss.Stream; import kiss.CompileError; +import kiss.Kiss; using kiss.Helpers; using kiss.Reader; using StringTools; // Field forms convert Kiss reader expressions into Haxe macro class fields -typedef FieldFormFunction = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> Field; +typedef FieldFormFunction = (wholeExp:ReaderExp, args:Array, k:KissState) -> Field; class FieldForms { public static function builtins() { @@ -61,7 +61,7 @@ class FieldForms { }; } - static function varOrProperty(formName:String, wholeExp:ReaderExp, args:Array, convert:ExprConversion):Field { + static function varOrProperty(formName:String, wholeExp:ReaderExp, args:Array, k:KissState):Field { wholeExp.checkNumArgs(2, 3, '($formName [optional :type] [variable] [optional: &mut] [value])'); var name = fieldName(formName, args[0]); @@ -74,12 +74,12 @@ class FieldForms { case TypedExp(type, _): Helpers.parseComplexType(type, args[0]); default: null; - }, convert(args[1])), + }, k.convert(args[1])), pos: Context.currentPos() }; } - static function funcOrMethod(formName:String, wholeExp:ReaderExp, args:Array, convert:ExprConversion):Field { + static function funcOrMethod(formName:String, wholeExp:ReaderExp, args:Array, k:KissState):Field { wholeExp.checkNumArgs(3, null, '($formName [optional :type] [name] [[argNames...]] [body...])'); var name = fieldName(formName, args[0]); @@ -88,7 +88,7 @@ class FieldForms { return { name: name, access: access, - kind: FFun(Helpers.makeFunction(args[0], args[1], args.slice(2), convert)), + kind: FFun(Helpers.makeFunction(args[0], args[1], args.slice(2), k)), pos: Context.currentPos() }; } diff --git a/src/kiss/Helpers.hx b/src/kiss/Helpers.hx index 77f009b1..5a44234a 100644 --- a/src/kiss/Helpers.hx +++ b/src/kiss/Helpers.hx @@ -4,7 +4,6 @@ import haxe.macro.Expr; import haxe.macro.Context; import kiss.Reader; import kiss.CompileError; -import kiss.Types; import kiss.Kiss; using kiss.Reader; @@ -56,7 +55,8 @@ class Helpers { } // TODO generic type parameter declarations - public static function makeFunction(?name:ReaderExp, argList:ReaderExp, body:Array, convert:ExprConversion):Function { + + public static function makeFunction(?name:ReaderExp, argList:ReaderExp, body:Array, k:KissState):Function { return { ret: if (name != null) switch (name.def) { case TypedExp(type, _): Helpers.parseComplexType(type, name); @@ -87,7 +87,7 @@ class Helpers { default: throw CompileError.fromExp(argList, 'expected an argument list'); }, - expr: EReturn(convert(CallExp(Symbol("begin").withPos(body[0].pos), body).withPos(body[0].pos))).withContextPos() + expr: EReturn(k.convert(CallExp(Symbol("begin").withPos(body[0].pos), body).withPos(body[0].pos))).withContextPos() } } diff --git a/src/kiss/Kiss.hx b/src/kiss/Kiss.hx index ec895930..adb4a619 100644 --- a/src/kiss/Kiss.hx +++ b/src/kiss/Kiss.hx @@ -8,13 +8,14 @@ import kiss.Reader; import kiss.FieldForms; import kiss.SpecialForms; import kiss.Macros; -import kiss.Types; import kiss.CompileError; using kiss.Helpers; using kiss.Reader; using tink.MacroApi; +typedef ExprConversion = (ReaderExp) -> Expr; + typedef KissState = { className:String, readTable:Map, @@ -90,7 +91,7 @@ class Kiss { var expandedExp = macros[mac](exp, args, k); if (expandedExp != null) readerExpToField(macros[mac](expandedExp, args, k), k) else null; case CallExp({pos: _, def: Symbol(formName)}, args) if (fieldForms.exists(formName)): - fieldForms[formName](exp, args, readerExpToHaxeExpr.bind(_, k)); + fieldForms[formName](exp, args, k); default: throw CompileError.fromExp(exp, 'invalid valid field form'); }; @@ -112,7 +113,7 @@ class Kiss { case CallExp({pos: _, def: Symbol(mac)}, args) if (macros.exists(mac)): convert(macros[mac](exp, args, k)); case CallExp({pos: _, def: Symbol(specialForm)}, args) if (specialForms.exists(specialForm)): - specialForms[specialForm](exp, args, convert); + specialForms[specialForm](exp, args, k); case CallExp(func, body): ECall(convert(func), [for (bodyExp in body) convert(bodyExp)]).withContextPos(); case ListExp(elements): diff --git a/src/kiss/SpecialForms.hx b/src/kiss/SpecialForms.hx index e307db6c..d24acd7a 100644 --- a/src/kiss/SpecialForms.hx +++ b/src/kiss/SpecialForms.hx @@ -3,7 +3,6 @@ package kiss; import haxe.macro.Expr; import haxe.macro.Context; import kiss.Reader; -import kiss.Types; import uuid.Uuid; using uuid.Uuid; @@ -11,28 +10,30 @@ using kiss.Reader; using kiss.Helpers; using kiss.Prelude; +import kiss.Kiss; + // Special forms convert Kiss reader expressions into Haxe macro expressions -typedef SpecialFormFunction = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> Expr; +typedef SpecialFormFunction = (wholeExp:ReaderExp, args:Array, k:KissState) -> Expr; class SpecialForms { public static function builtins() { var map:Map = []; - map["begin"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["begin"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { // Sometimes empty blocks are useful, so a checkNumArgs() seems unnecessary here for now. - EBlock([for (bodyExp in args) convert(bodyExp)]).withContextPos(); + EBlock([for (bodyExp in args) k.convert(bodyExp)]).withContextPos(); }; - map["nth"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["nth"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, 2, "(nth [list] [idx])"); - EArray(convert(args[0]), convert(args[1])).withContextPos(); + EArray(k.convert(args[0]), k.convert(args[1])).withContextPos(); }; function makeQuickNth(idx:Int, name:String) { - map[name] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map[name] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(1, 1, '($name [list])'); - EArray(convert(args[0]), macro $v{idx}).withContextPos(); + EArray(k.convert(args[0]), macro $v{idx}).withContextPos(); }; } makeQuickNth(0, "first"); @@ -51,28 +52,28 @@ class SpecialForms { // TODO special form for object declaration - map["new"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["new"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(1, null, '(new [type] [constructorArgs...])'); var classType = switch (args[0].def) { case Symbol(name): name; default: throw CompileError.fromExp(args[0], 'first arg in (new [type] ...) should be a class to instantiate'); }; - ENew(Helpers.parseTypePath(classType, args[0]), args.slice(1).map(convert)).withContextPos(); + ENew(Helpers.parseTypePath(classType, args[0]), args.slice(1).map(k.convert)).withContextPos(); }; - map["set"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["set"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, 2, "(set [variable] [value])"); - EBinop(OpAssign, convert(args[0]), convert(args[1])).withContextPos(); + EBinop(OpAssign, k.convert(args[0]), k.convert(args[1])).withContextPos(); }; - function toVar(nameExp:ReaderExp, valueExp:ReaderExp, convert:ExprConversion, ?isFinal:Bool):Var { + function toVar(nameExp:ReaderExp, valueExp:ReaderExp, k:KissState, ?isFinal:Bool):Var { // This check seems like unnecessary repetition but it's not. It allows is so that individual destructured bindings can specify mutability return if (isFinal == null) { switch (nameExp.def) { case MetaExp("mut", innerNameExp): - toVar(innerNameExp, valueExp, convert, false); + toVar(innerNameExp, valueExp, k, false); default: - toVar(nameExp, valueExp, convert, true); + toVar(nameExp, valueExp, k, true); }; } else { name: switch (nameExp.def) { @@ -87,29 +88,29 @@ class SpecialForms { default: null; }, isFinal: isFinal, - expr: convert(valueExp) + expr: k.convert(valueExp) }; } - function toVars(namesExp:ReaderExp, valueExp:ReaderExp, convert:ExprConversion, ?isFinal:Bool):Array { + function toVars(namesExp:ReaderExp, valueExp:ReaderExp, k:KissState, ?isFinal:Bool):Array { return if (isFinal == null) { switch (namesExp.def) { case MetaExp("mut", innerNamesExp): - toVars(innerNamesExp, valueExp, convert, false); + toVars(innerNamesExp, valueExp, k, false); default: - toVars(namesExp, valueExp, convert, true); + toVars(namesExp, valueExp, k, true); }; } else { switch (namesExp.def) { case Symbol(_) | TypedExp(_, {pos: _, def: Symbol(_)}): - [toVar(namesExp, valueExp, convert, isFinal)]; + [toVar(namesExp, valueExp, k, isFinal)]; case ListExp(nameExps): var idx = 0; [ for (nameExp in nameExps) toVar(nameExp, CallExp(Symbol("nth").withPosOf(valueExp), [valueExp, Symbol(Std.string(idx++)).withPosOf(valueExp)]).withPosOf(valueExp), - convert, if (isFinal == false) false else null) + k, if (isFinal == false) false else null) ]; default: throw CompileError.fromExp(namesExp, "Can only bind variables to a symbol or list of symbols for destructuring"); @@ -117,12 +118,12 @@ class SpecialForms { }; } - map["deflocal"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["deflocal"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, 3, "(deflocal [optional :type] [variable] [optional: &mut] [value])"); - EVars(toVars(args[0], args[1], convert)).withContextPos(); + EVars(toVars(args[0], args[1], k)).withContextPos(); }; - map["let"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["let"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, null, "(let [[bindings...]] [body...])"); var bindingList = switch (args[0].def) { case ListExp(bindingExps) if (bindingExps.length > 0 && bindingExps.length % 2 == 0): @@ -133,7 +134,7 @@ class SpecialForms { var bindingPairs = bindingList.groups(2); var varDefs = []; for (bindingPair in bindingPairs) { - varDefs = varDefs.concat(toVars(bindingPair[0], bindingPair[1], convert)); + varDefs = varDefs.concat(toVars(bindingPair[0], bindingPair[1], k)); } var body = args.slice(1); @@ -141,15 +142,15 @@ class SpecialForms { throw CompileError.fromArgs(args, '(let....) expression needs a body'); } - EBlock([EVars(varDefs).withContextPos(), EBlock(body.map(convert)).withContextPos()]).withContextPos(); + EBlock([EVars(varDefs).withContextPos(), EBlock(body.map(k.convert)).withContextPos()]).withContextPos(); }; - map["lambda"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["lambda"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, null, "(lambda [[argsNames...]] [body...])"); - EFunction(FArrow, Helpers.makeFunction(null, args[0], args.slice(1), convert)).withContextPos(); + EFunction(FArrow, Helpers.makeFunction(null, args[0], args.slice(1), k)).withContextPos(); }; - function forExpr(formName:String, wholeExp:ReaderExp, args:Array, convert:ExprConversion) { + function forExpr(formName:String, wholeExp:ReaderExp, args:Array, k:KissState) { wholeExp.checkNumArgs(3, null, '($formName [varName] [list] [body...])'); var uniqueVarName = "_" + Uuid.v4().toShort(); var namesExp = args[0]; @@ -157,30 +158,30 @@ class SpecialForms { var bodyExps = args.slice(2); bodyExps.insert(0, CallExp(Symbol("deflocal").withPosOf(args[2]), [namesExp, Symbol(uniqueVarName).withPosOf(args[2])]).withPosOf(args[2])); var body = CallExp(Symbol("begin").withPosOf(args[2]), bodyExps).withPosOf(args[2]); - return EFor(EBinop(OpIn, EConst(CIdent(uniqueVarName)).withContextPos(), convert(listExp)).withContextPos(), convert(body)).withContextPos(); + return EFor(EBinop(OpIn, EConst(CIdent(uniqueVarName)).withContextPos(), k.convert(listExp)).withContextPos(), k.convert(body)).withContextPos(); } map["doFor"] = forExpr.bind("doFor"); - map["for"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { - EArrayDecl([forExpr("for", wholeExp, args, convert)]).withContextPos(); + map["for"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { + EArrayDecl([forExpr("for", wholeExp, args, k)]).withContextPos(); }; // TODO (case... ) for switch // Type check syntax: - map["the"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["the"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, 2, '(the [type] [value])'); - ECheckType(convert(args[1]), switch (args[0].def) { + ECheckType(k.convert(args[1]), switch (args[0].def) { case Symbol(type): Helpers.parseComplexType(type, args[0]); default: throw CompileError.fromExp(args[0], 'first argument to (the... ) should be a valid type'); }).withContextPos(); }; - map["try"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["try"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(1, null, "(try [thing] [catches...])"); var tryKissExp = args[0]; var catchKissExps = args.slice(1); - ETry(convert(tryKissExp), [ + ETry(k.convert(tryKissExp), [ for (catchKissExp in catchKissExps) { switch (catchKissExp.def) { case CallExp({pos: _, def: Symbol("catch")}, catchArgs): @@ -199,7 +200,7 @@ class SpecialForms { Helpers.parseComplexType(type, catchArgs[0]); default: null; }, - expr: convert(CallExp(Symbol("begin").withPos(catchArgs[1].pos), catchArgs.slice(1)).withPos(catchArgs[1].pos)) + expr: k.convert(CallExp(Symbol("begin").withPos(catchArgs[1].pos), catchArgs.slice(1)).withPos(catchArgs[1].pos)) }; default: throw CompileError.fromExp(catchKissExp, @@ -209,11 +210,11 @@ class SpecialForms { ]).withContextPos(); }; - map["throw"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["throw"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { if (args.length != 1) { throw CompileError.fromExp(wholeExp, 'throw expression should only throw one value'); } - EThrow(convert(args[0])).withContextPos(); + EThrow(k.convert(args[0])).withContextPos(); }; map["<"] = foldComparison("_min"); @@ -222,13 +223,13 @@ class SpecialForms { map[">="] = foldComparison("max"); map["="] = foldComparison("_eq"); - map["if"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["if"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(2, 3, '(if [cond] [then] [?else])'); - var condition = macro Prelude.truthy(${convert(args[0])}); - var thenExp = convert(args[1]); + var condition = macro Prelude.truthy(${k.convert(args[0])}); + var thenExp = k.convert(args[1]); var elseExp = if (args.length > 2) { - convert(args[2]); + k.convert(args[2]); } else { // Kiss (if... ) expressions all need to generate a Haxe else block // to make sure they always return something @@ -241,10 +242,10 @@ class SpecialForms { $elseExp; }; - map["not"] = (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + map["not"] = (wholeExp:ReaderExp, args:Array, k:KissState) -> { if (args.length != 1) throw CompileError.fromExp(wholeExp, '(not... ) only takes one argument, not $args'); - var condition = convert(args[0]); + var condition = k.convert(args[0]); var truthyExp = macro Prelude.truthy($condition); macro !$truthyExp; }; @@ -253,9 +254,9 @@ class SpecialForms { } static function foldComparison(func:String) { - return (wholeExp:ReaderExp, args:Array, convert:ExprConversion) -> { + return (wholeExp:ReaderExp, args:Array, k:KissState) -> { wholeExp.checkNumArgs(1, null); - EBinop(OpEq, convert(args[0]), convert(CallExp(Symbol(func).withPosOf(wholeExp), args).withPosOf(wholeExp))).withContextPos(); + EBinop(OpEq, k.convert(args[0]), k.convert(CallExp(Symbol(func).withPosOf(wholeExp), args).withPosOf(wholeExp))).withContextPos(); }; } } diff --git a/src/kiss/Types.hx b/src/kiss/Types.hx deleted file mode 100644 index 83e71b6f..00000000 --- a/src/kiss/Types.hx +++ /dev/null @@ -1,7 +0,0 @@ -package kiss; - -import haxe.macro.Expr; -import kiss.Reader; - -// A lot of special forms need to convert expressions recursively, so they get passed an ExprConversion -typedef ExprConversion = (ReaderExp) -> Expr;