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;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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));
|
||||||
|
@@ -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();
|
||||||
|
@@ -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) -> {
|
||||||
|
Reference in New Issue
Block a user