refactor to store minArgs, maxArgs, expectedForm, and a docstring of forms. close #55
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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));
|
||||
|
@@ -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();
|
||||
|
@@ -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) -> {
|
||||
|
Reference in New Issue
Block a user