refactor to store minArgs, maxArgs, expectedForm, and a docstring of forms. close #55

This commit is contained in:
2022-06-04 17:07:44 +00:00
parent 6d7bc22fa2
commit 7ba7a84734
4 changed files with 90 additions and 49 deletions

View File

@@ -17,7 +17,7 @@ using StringTools;
typedef FieldFormFunction = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> Field; typedef FieldFormFunction = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> Field;
class FieldForms { class FieldForms {
public static function builtins() { public static function addBuiltins(k:KissState) {
var map:Map<String, FieldFormFunction> = []; var map:Map<String, FieldFormFunction> = [];
function renameAndDeprecate(oldName:String, newName:String) { function renameAndDeprecate(oldName:String, newName:String) {
@@ -27,17 +27,14 @@ class FieldForms {
form(wholeExp, args, k); form(wholeExp, args, k);
} }
map[newName] = form; map[newName] = form;
k.formDocs[newName] = k.formDocs[oldName];
} }
map["defvar"] = varOrProperty.bind("var"); varOrProperty("var", k);
renameAndDeprecate("defvar", "var"); varOrProperty("prop", k);
map["defprop"] = varOrProperty.bind("prop");
renameAndDeprecate("defprop", "prop");
map["defun"] = funcOrMethod.bind("function"); funcOrMethod("function", k);
renameAndDeprecate("defun", "function"); funcOrMethod("method", k);
map["defmethod"] = funcOrMethod.bind("method");
renameAndDeprecate("defmethod", "method");
return map; return map;
} }
@@ -98,45 +95,48 @@ class FieldForms {
} }
} }
static function varOrProperty(formName:String, wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState):Field { static function varOrProperty(formName:String, k:KissState) {
wholeExp.checkNumArgs(1, 3, '($formName [optional: &mut] [optional :type] [variable] [optional value])'); k.doc(formName, 1, 3, '($formName [optional: &mut] [optional :type] [variable] [optional value])');
k.fieldForms[formName] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
var name = Helpers.varName(formName, args[0]);
var access = fieldAccess(formName, name, args[0]);
var name = Helpers.varName(formName, args[0]); ({
var access = fieldAccess(formName, name, args[0]); name: name,
access: access,
return { kind: FVar(Helpers.explicitType(args[0]), if (args.length > 1) k.convert(args[1]) else null),
name: name, pos: wholeExp.macroPos()
access: access, } : Field);
kind: FVar(Helpers.explicitType(args[0]), if (args.length > 1) k.convert(args[1]) else null), }
pos: wholeExp.macroPos()
};
} }
static function funcOrMethod(formName:String, wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState):Field { static function funcOrMethod(formName:String, k:KissState) {
wholeExp.checkNumArgs(2, null, '($formName [optional :type] [name] [[argNames...]] [body...])'); k.doc(formName, 2, null, '($formName [optional &dynamic] [optional :type] [name] [[argNames...]] [body...])');
k.fieldForms[formName] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
var name = Helpers.varName(formName, args[0]); var name = Helpers.varName(formName, args[0]);
var access = fieldAccess(formName, name, args[0]); var access = fieldAccess(formName, name, args[0]);
var inStaticFunction = access.indexOf(AStatic) != -1; var inStaticFunction = access.indexOf(AStatic) != -1;
var returnsValue = !isVoid(args[0]); var returnsValue = !isVoid(args[0]);
var wasInStatic = k.inStaticFunction; var wasInStatic = k.inStaticFunction;
var f = { var f:Field = {
name: name, name: name,
access: access, access: access,
kind: FFun( kind: FFun(
Helpers.makeFunction( Helpers.makeFunction(
args[0], args[0],
returnsValue, returnsValue,
args[1], args[1],
args.slice(2), args.slice(2),
k.forStaticFunction(inStaticFunction), k.forStaticFunction(inStaticFunction),
formName)), formName)),
pos: wholeExp.macroPos() pos: wholeExp.macroPos()
}; };
k = k.forStaticFunction(wasInStatic); k = k.forStaticFunction(wasInStatic);
return f; return f;
}
} }
} }

View File

@@ -22,6 +22,13 @@ using haxe.io.Path;
typedef ExprConversion = (ReaderExp) -> Expr; typedef ExprConversion = (ReaderExp) -> Expr;
typedef FormDoc = {
minArgs:Null<Int>,
maxArgs:Null<Int>,
?expectedForm:String,
?doc:String
};
typedef KissState = { typedef KissState = {
className:String, className:String,
file:String, file:String,
@@ -32,6 +39,8 @@ typedef KissState = {
fieldForms:Map<String, FieldFormFunction>, fieldForms:Map<String, FieldFormFunction>,
specialForms:Map<String, SpecialFormFunction>, specialForms:Map<String, SpecialFormFunction>,
macros:Map<String, MacroFunction>, macros:Map<String, MacroFunction>,
formDocs:Map<String, FormDoc>,
doc:(String, Null<Int>, Null<Int>, ?String, ?String)->Void,
wrapListExps:Bool, wrapListExps:Bool,
loadedFiles:Map<String, Null<ReaderExp>>, loadedFiles:Map<String, Null<ReaderExp>>,
callAliases:Map<String, ReaderExpDef>, callAliases:Map<String, ReaderExpDef>,
@@ -59,9 +68,11 @@ class Kiss {
startOfLineReadTable: new ReadTable(), startOfLineReadTable: new ReadTable(),
startOfFileReadTable: new ReadTable(), startOfFileReadTable: new ReadTable(),
endOfFileReadTable: new ReadTable(), endOfFileReadTable: new ReadTable(),
fieldForms: FieldForms.builtins(), fieldForms: new Map(),
specialForms: SpecialForms.builtins(), specialForms: null,
macros: Macros.builtins(), macros: null,
formDocs: new Map(),
doc: null,
wrapListExps: true, wrapListExps: true,
loadedFiles: new Map<String, ReaderExp>(), loadedFiles: new Map<String, ReaderExp>(),
// Helpful built-in aliases // Helpful built-in aliases
@@ -131,6 +142,20 @@ class Kiss {
inStaticFunction: false inStaticFunction: false
}; };
k.doc = (form:String, minArgs:Null<Int>, maxArgs:Null<Int>, expectedForm = "", doc = "") -> {
k.formDocs[form] = {
minArgs: minArgs,
maxArgs: maxArgs,
expectedForm: expectedForm,
doc: doc
};
return;
};
FieldForms.addBuiltins(k);
k.specialForms = SpecialForms.builtins(k);
k.macros = Macros.builtins(k);
return k; return k;
} }
@@ -333,9 +358,20 @@ class Kiss {
var macros = k.macros; var macros = k.macros;
var fieldForms = k.fieldForms; var fieldForms = k.fieldForms;
var specialForms = k.specialForms; var specialForms = k.specialForms;
var formDocs = k.formDocs;
// Bind the table arguments of this function for easy recursive calling/passing // Bind the table arguments of this function for easy recursive calling/passing
var convert = readerExpToHaxeExpr.bind(_, k); var convert = readerExpToHaxeExpr.bind(_, k);
function checkNumArgs(form:String) {
if (formDocs.exists(form)) {
var docs = formDocs[form];
// null docs can get passed around by renameAndDeprecate functions. a check here is more DRY
if (docs != null)
exp.checkNumArgs(docs.minArgs, docs.maxArgs, docs.expectedForm);
}
}
if (k.hscript) if (k.hscript)
exp = Helpers.removeTypeAnnotations(exp); exp = Helpers.removeTypeAnnotations(exp);
@@ -355,11 +391,13 @@ class Kiss {
case StrExp(s): case StrExp(s):
EConst(CString(s)).withMacroPosOf(exp); EConst(CString(s)).withMacroPosOf(exp);
case CallExp({pos: _, def: Symbol(ff)}, args) if (fieldForms.exists(ff)): case CallExp({pos: _, def: Symbol(ff)}, args) if (fieldForms.exists(ff)):
checkNumArgs(ff);
var field = fieldForms[ff](exp, args.copy(), k); var field = fieldForms[ff](exp, args.copy(), k);
k.fieldList.push(field); k.fieldList.push(field);
k.fieldDict[field.name] = field; k.fieldDict[field.name] = field;
none; // Field forms are no-ops none; // Field forms are no-ops
case CallExp({pos: _, def: Symbol(mac)}, args) if (macros.exists(mac)): case CallExp({pos: _, def: Symbol(mac)}, args) if (macros.exists(mac)):
checkNumArgs(mac);
macroUsed = true; macroUsed = true;
var expanded = macros[mac](exp, args.copy(), k); var expanded = macros[mac](exp, args.copy(), k);
if (expanded != null) { if (expanded != null) {
@@ -368,6 +406,7 @@ class Kiss {
none; none;
}; };
case CallExp({pos: _, def: Symbol(specialForm)}, args) if (specialForms.exists(specialForm)): case CallExp({pos: _, def: Symbol(specialForm)}, args) if (specialForms.exists(specialForm)):
checkNumArgs(specialForm);
specialForms[specialForm](exp, args.copy(), k); specialForms[specialForm](exp, args.copy(), k);
case CallExp({pos: _, def: Symbol(alias)}, args) if (k.callAliases.exists(alias)): case CallExp({pos: _, def: Symbol(alias)}, args) if (k.callAliases.exists(alias)):
convert(CallExp(k.callAliases[alias].withPosOf(exp), args).withPosOf(exp)); convert(CallExp(k.callAliases[alias].withPosOf(exp), args).withPosOf(exp));

View File

@@ -22,7 +22,7 @@ using tink.MacroApi;
typedef MacroFunction = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> Null<ReaderExp>; typedef MacroFunction = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> Null<ReaderExp>;
class Macros { class Macros {
public static function builtins() { public static function builtins(k:KissState) {
var macros:Map<String, MacroFunction> = []; var macros:Map<String, MacroFunction> = [];
function renameAndDeprecate(oldName:String, newName:String) { function renameAndDeprecate(oldName:String, newName:String) {
@@ -32,6 +32,7 @@ class Macros {
form(wholeExp, args, k); form(wholeExp, args, k);
} }
macros[newName] = form; macros[newName] = form;
k.formDocs[newName] = k.formDocs[oldName];
} }
macros["load"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> { macros["load"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
@@ -265,8 +266,8 @@ class Macros {
macros["or"] = _or; macros["or"] = _or;
k.doc("and", 1, null, "(and <v1> <values...>)");
function _and(wholeExp:ReaderExp, args:Array<ReaderExp>, k) { function _and(wholeExp:ReaderExp, args:Array<ReaderExp>, k) {
wholeExp.checkNumArgs(1, null, "(and <v1> <values...>)");
var b = wholeExp.expBuilder(); var b = wholeExp.expBuilder();
var uniqueVarSymbol = b.symbol(); var uniqueVarSymbol = b.symbol();

View File

@@ -18,7 +18,7 @@ using tink.MacroApi;
typedef SpecialFormFunction = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> Expr; typedef SpecialFormFunction = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> Expr;
class SpecialForms { class SpecialForms {
public static function builtins() { public static function builtins(k:KissState) {
var map:Map<String, SpecialFormFunction> = []; var map:Map<String, SpecialFormFunction> = [];
function renameAndDeprecate(oldName:String, newName:String) { function renameAndDeprecate(oldName:String, newName:String) {
@@ -28,6 +28,7 @@ class SpecialForms {
form(wholeExp, args, k); form(wholeExp, args, k);
} }
map[newName] = form; map[newName] = form;
k.formDocs[newName] = k.formDocs[oldName];
} }
map["begin"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> { map["begin"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
@@ -47,8 +48,8 @@ class SpecialForms {
function arrayAccess(wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) { function arrayAccess(wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) {
return EArray(k.convert(args[0]), k.convert(args[1])).withMacroPosOf(wholeExp); return EArray(k.convert(args[0]), k.convert(args[1])).withMacroPosOf(wholeExp);
}; };
k.doc("nth", 2, 2, "(nth [list] [idx])");
map["nth"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> { map["nth"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(2, 2, "(nth [list] [idx])");
arrayAccess(wholeExp, args, k); arrayAccess(wholeExp, args, k);
}; };
map["dictGet"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> { map["dictGet"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {