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

View File

@@ -22,6 +22,13 @@ using haxe.io.Path;
typedef ExprConversion = (ReaderExp) -> Expr;
typedef FormDoc = {
minArgs:Null<Int>,
maxArgs:Null<Int>,
?expectedForm:String,
?doc:String
};
typedef KissState = {
className:String,
file:String,
@@ -32,6 +39,8 @@ typedef KissState = {
fieldForms:Map<String, FieldFormFunction>,
specialForms:Map<String, SpecialFormFunction>,
macros:Map<String, MacroFunction>,
formDocs:Map<String, FormDoc>,
doc:(String, Null<Int>, Null<Int>, ?String, ?String)->Void,
wrapListExps:Bool,
loadedFiles:Map<String, Null<ReaderExp>>,
callAliases:Map<String, ReaderExpDef>,
@@ -59,9 +68,11 @@ class Kiss {
startOfLineReadTable: new ReadTable(),
startOfFileReadTable: new ReadTable(),
endOfFileReadTable: new ReadTable(),
fieldForms: FieldForms.builtins(),
specialForms: SpecialForms.builtins(),
macros: Macros.builtins(),
fieldForms: new Map(),
specialForms: null,
macros: null,
formDocs: new Map(),
doc: null,
wrapListExps: true,
loadedFiles: new Map<String, ReaderExp>(),
// Helpful built-in aliases
@@ -131,6 +142,20 @@ class Kiss {
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;
}
@@ -333,9 +358,20 @@ class Kiss {
var macros = k.macros;
var fieldForms = k.fieldForms;
var specialForms = k.specialForms;
var formDocs = k.formDocs;
// Bind the table arguments of this function for easy recursive calling/passing
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)
exp = Helpers.removeTypeAnnotations(exp);
@@ -355,11 +391,13 @@ class Kiss {
case StrExp(s):
EConst(CString(s)).withMacroPosOf(exp);
case CallExp({pos: _, def: Symbol(ff)}, args) if (fieldForms.exists(ff)):
checkNumArgs(ff);
var field = fieldForms[ff](exp, args.copy(), k);
k.fieldList.push(field);
k.fieldDict[field.name] = field;
none; // Field forms are no-ops
case CallExp({pos: _, def: Symbol(mac)}, args) if (macros.exists(mac)):
checkNumArgs(mac);
macroUsed = true;
var expanded = macros[mac](exp, args.copy(), k);
if (expanded != null) {
@@ -368,6 +406,7 @@ class Kiss {
none;
};
case CallExp({pos: _, def: Symbol(specialForm)}, args) if (specialForms.exists(specialForm)):
checkNumArgs(specialForm);
specialForms[specialForm](exp, args.copy(), k);
case CallExp({pos: _, def: Symbol(alias)}, args) if (k.callAliases.exists(alias)):
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>;
class Macros {
public static function builtins() {
public static function builtins(k:KissState) {
var macros:Map<String, MacroFunction> = [];
function renameAndDeprecate(oldName:String, newName:String) {
@@ -32,6 +32,7 @@ class Macros {
form(wholeExp, args, k);
}
macros[newName] = form;
k.formDocs[newName] = k.formDocs[oldName];
}
macros["load"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
@@ -265,8 +266,8 @@ class Macros {
macros["or"] = _or;
k.doc("and", 1, null, "(and <v1> <values...>)");
function _and(wholeExp:ReaderExp, args:Array<ReaderExp>, k) {
wholeExp.checkNumArgs(1, null, "(and <v1> <values...>)");
var b = wholeExp.expBuilder();
var uniqueVarSymbol = b.symbol();

View File

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