experimental type aliases
This commit is contained in:
@@ -186,7 +186,7 @@ class EmbeddedScript {
|
|||||||
ret: null,
|
ret: null,
|
||||||
args: [
|
args: [
|
||||||
{
|
{
|
||||||
type: Helpers.parseComplexType("(()->Void)->Void", null),
|
type: Helpers.parseComplexType("(()->Void)->Void", k, null),
|
||||||
name: "c"
|
name: "c"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -207,10 +207,10 @@ class EmbeddedScript {
|
|||||||
name: "fork",
|
name: "fork",
|
||||||
access: [APublic],
|
access: [APublic],
|
||||||
kind: FFun({
|
kind: FFun({
|
||||||
ret: Helpers.parseComplexType("Array<EmbeddedScript>", null),
|
ret: Helpers.parseComplexType("Array<EmbeddedScript>", k, null),
|
||||||
args: [
|
args: [
|
||||||
{
|
{
|
||||||
type: Helpers.parseComplexType("Array<Command>", null),
|
type: Helpers.parseComplexType("Array<Command>", k, null),
|
||||||
name: "commands"
|
name: "commands"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@@ -103,7 +103,7 @@ class FieldForms {
|
|||||||
checkPrintFieldsCalledWarning(name, wholeExp, k);
|
checkPrintFieldsCalledWarning(name, wholeExp, k);
|
||||||
var access = fieldAccess(formName, name, args[0]);
|
var access = fieldAccess(formName, name, args[0]);
|
||||||
|
|
||||||
var type = Helpers.explicitType(args[0]);
|
var type = Helpers.explicitType(args[0], k);
|
||||||
k.addVarInScope(
|
k.addVarInScope(
|
||||||
{name: name, type: type},
|
{name: name, type: type},
|
||||||
false,
|
false,
|
||||||
|
@@ -49,8 +49,10 @@ class Helpers {
|
|||||||
return s.charAt(0) == s.charAt(0).toUpperCase();
|
return s.charAt(0) == s.charAt(0).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function parseTypePath(path:String, ?from:ReaderExp):TypePath {
|
public static function parseTypePath(path:String, k:KissState, ?from:ReaderExp):TypePath {
|
||||||
return switch (parseComplexType(path, from)) {
|
if (k.typeAliases.exists(path))
|
||||||
|
path = k.typeAliases[path];
|
||||||
|
return switch (parseComplexType(path, k, from)) {
|
||||||
case TPath(path):
|
case TPath(path):
|
||||||
path;
|
path;
|
||||||
default:
|
default:
|
||||||
@@ -63,7 +65,10 @@ class Helpers {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function parseComplexType(path:String, ?from:ReaderExp, mustResolve=false):ComplexType {
|
public static function parseComplexType(path:String, k:KissState, ?from:ReaderExp, mustResolve=false):ComplexType {
|
||||||
|
if (k.typeAliases.exists(path))
|
||||||
|
path = k.typeAliases[path];
|
||||||
|
|
||||||
// Trick Haxe into parsing it for us:
|
// Trick Haxe into parsing it for us:
|
||||||
var typeCheckStr = 'var thing:$path;';
|
var typeCheckStr = 'var thing:$path;';
|
||||||
var errorMessage = 'Haxe could not parse a complex type from `$path` in `${typeCheckStr}`';
|
var errorMessage = 'Haxe could not parse a complex type from `$path` in `${typeCheckStr}`';
|
||||||
@@ -102,20 +107,22 @@ class Helpers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function explicitTypeString(nameExp:ReaderExp):String {
|
public static function explicitTypeString(nameExp:ReaderExp, k:KissState):String {
|
||||||
return switch (nameExp.def) {
|
return switch (nameExp.def) {
|
||||||
case MetaExp(_, innerExp):
|
case MetaExp(_, innerExp):
|
||||||
explicitTypeString(innerExp);
|
explicitTypeString(innerExp, k);
|
||||||
|
case TypedExp(type, _) if (k.typeAliases.exists(type)):
|
||||||
|
k.typeAliases[type];
|
||||||
case TypedExp(type, _):
|
case TypedExp(type, _):
|
||||||
type;
|
type;
|
||||||
default: null;
|
default: null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function explicitType(nameExp:ReaderExp):ComplexType {
|
public static function explicitType(nameExp:ReaderExp, k:KissState):ComplexType {
|
||||||
var string = explicitTypeString(nameExp);
|
var string = explicitTypeString(nameExp, k);
|
||||||
if (string == null) return null;
|
if (string == null) return null;
|
||||||
return Helpers.parseComplexType(string, nameExp);
|
return Helpers.parseComplexType(string, k, nameExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function varName(formName:String, nameExp:ReaderExp, nameType = "variable") {
|
public static function varName(formName:String, nameExp:ReaderExp, nameType = "variable") {
|
||||||
@@ -129,17 +136,19 @@ class Helpers {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function makeTypeParam(param:ReaderExp, ?constraints:Array<ComplexType> = null):TypeParamDecl {
|
public static function makeTypeParam(param:ReaderExp, k:KissState, ?constraints:Array<ComplexType> = null):TypeParamDecl {
|
||||||
if (constraints == null) constraints = [];
|
if (constraints == null) constraints = [];
|
||||||
switch (param.def) {
|
switch (param.def) {
|
||||||
case Symbol(name):
|
case Symbol(name):
|
||||||
|
if (k.typeAliases.exists(name))
|
||||||
|
name = k.typeAliases[name];
|
||||||
return {
|
return {
|
||||||
name: name,
|
name: name,
|
||||||
constraints: constraints
|
constraints: constraints
|
||||||
};
|
};
|
||||||
case TypedExp(type, param):
|
case TypedExp(type, param):
|
||||||
constraints.push(parseComplexType(type));
|
constraints.push(parseComplexType(type, k));
|
||||||
return makeTypeParam(param, constraints);
|
return makeTypeParam(param, k, constraints);
|
||||||
default:
|
default:
|
||||||
throw KissError.fromExp(param, "expected <GenericTypeName> or :<Constraint> <GenericTypeName>");
|
throw KissError.fromExp(param, "expected <GenericTypeName> or :<Constraint> <GenericTypeName>");
|
||||||
}
|
}
|
||||||
@@ -152,7 +161,7 @@ class Helpers {
|
|||||||
"";
|
"";
|
||||||
};
|
};
|
||||||
|
|
||||||
var params = [for (p in typeParams) makeTypeParam(p)];
|
var params = [for (p in typeParams) makeTypeParam(p, k)];
|
||||||
|
|
||||||
var numArgs = 0;
|
var numArgs = 0;
|
||||||
// Once the &opt meta appears, all following arguments are optional until &rest
|
// Once the &opt meta appears, all following arguments are optional until &rest
|
||||||
@@ -171,7 +180,7 @@ class Helpers {
|
|||||||
throw KissError.fromExp(funcArg, "lambda does not support &rest arguments");
|
throw KissError.fromExp(funcArg, "lambda does not support &rest arguments");
|
||||||
}
|
}
|
||||||
|
|
||||||
var typeOfRestArg = explicitTypeString(funcArg);
|
var typeOfRestArg = explicitTypeString(funcArg, k);
|
||||||
var isDynamicArray = switch (typeOfRestArg) {
|
var isDynamicArray = switch (typeOfRestArg) {
|
||||||
case "Array<Dynamic>" | "kiss.List<Dynamic>" | "List<Dynamic>":
|
case "Array<Dynamic>" | "kiss.List<Dynamic>" | "List<Dynamic>":
|
||||||
true;
|
true;
|
||||||
@@ -219,7 +228,7 @@ class Helpers {
|
|||||||
},
|
},
|
||||||
type: switch (funcArg.def) {
|
type: switch (funcArg.def) {
|
||||||
case TypedExp(type, _):
|
case TypedExp(type, _):
|
||||||
Helpers.parseComplexType(type, funcArg);
|
Helpers.parseComplexType(type, k, funcArg);
|
||||||
default: null;
|
default: null;
|
||||||
},
|
},
|
||||||
opt: opt
|
opt: opt
|
||||||
@@ -269,7 +278,7 @@ class Helpers {
|
|||||||
// But setting null arguments to default values is so common, and arguments are not settable references,
|
// But setting null arguments to default values is so common, and arguments are not settable references,
|
||||||
// so function args are not immutable.
|
// so function args are not immutable.
|
||||||
return {
|
return {
|
||||||
ret: if (name != null) Helpers.explicitType(name) else null,
|
ret: if (name != null) Helpers.explicitType(name, k) else null,
|
||||||
args: args,
|
args: args,
|
||||||
expr: expr,
|
expr: expr,
|
||||||
params: params
|
params: params
|
||||||
@@ -470,14 +479,14 @@ class Helpers {
|
|||||||
}
|
}
|
||||||
// hscript.Interp is very finicky about some edge cases.
|
// hscript.Interp is very finicky about some edge cases.
|
||||||
// This function handles them
|
// This function handles them
|
||||||
private static function mapForInterp(expr:Expr):Expr {
|
private static function mapForInterp(expr:Expr, k:KissState):Expr {
|
||||||
return expr.map(subExp -> {
|
return expr.map(subExp -> {
|
||||||
switch (subExp.expr) {
|
switch (subExp.expr) {
|
||||||
case ETry(e, catches):
|
case ETry(e, catches):
|
||||||
catches = [for (c in catches) {
|
catches = [for (c in catches) {
|
||||||
// hscript.Parser expects :Dynamic after the catch varname
|
// hscript.Parser expects :Dynamic after the catch varname
|
||||||
{
|
{
|
||||||
type: Helpers.parseComplexType("Dynamic"),
|
type: Helpers.parseComplexType("Dynamic", k),
|
||||||
name: c.name,
|
name: c.name,
|
||||||
expr: c.expr
|
expr: c.expr
|
||||||
};
|
};
|
||||||
@@ -486,14 +495,14 @@ class Helpers {
|
|||||||
pos: subExp.pos,
|
pos: subExp.pos,
|
||||||
expr: ETry(e, catches)
|
expr: ETry(e, catches)
|
||||||
};
|
};
|
||||||
default: mapForInterp(subExp);
|
default: mapForInterp(subExp, k);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static var parser = new Parser();
|
static var parser = new Parser();
|
||||||
static function compileTimeHScript(exp:ReaderExp, k:KissState) {
|
static function compileTimeHScript(exp:ReaderExp, k:KissState) {
|
||||||
var hscriptExp = mapForInterp(k.forMacroEval().convert(exp));
|
var hscriptExp = mapForInterp(k.forMacroEval().convert(exp), k);
|
||||||
var code = hscriptExp.toString(); // tink_macro to the rescue
|
var code = hscriptExp.toString(); // tink_macro to the rescue
|
||||||
#if macrotest
|
#if macrotest
|
||||||
Prelude.print("Compile-time hscript: " + code);
|
Prelude.print("Compile-time hscript: " + code);
|
||||||
|
@@ -51,6 +51,7 @@ typedef KissState = {
|
|||||||
loadedFiles:Map<String, Null<ReaderExp>>,
|
loadedFiles:Map<String, Null<ReaderExp>>,
|
||||||
callAliases:Map<String, ReaderExpDef>,
|
callAliases:Map<String, ReaderExpDef>,
|
||||||
identAliases:Map<String, ReaderExpDef>,
|
identAliases:Map<String, ReaderExpDef>,
|
||||||
|
typeAliases:Map<String, String>,
|
||||||
fieldList:Array<Field>,
|
fieldList:Array<Field>,
|
||||||
// TODO This map was originally created to track whether the programmer wrote their own main function, but could also
|
// TODO This map was originally created to track whether the programmer wrote their own main function, but could also
|
||||||
// be used to allow macros to edit fields that were already defined (for instance, to decorate a function or add something
|
// be used to allow macros to edit fields that were already defined (for instance, to decorate a function or add something
|
||||||
@@ -182,6 +183,7 @@ class Kiss {
|
|||||||
/* concat used to live here as an alias but now it is in a macro that also
|
/* concat used to live here as an alias but now it is in a macro that also
|
||||||
applies (the Array<Dynamic>) to the result */
|
applies (the Array<Dynamic>) to the result */
|
||||||
],
|
],
|
||||||
|
typeAliases: new Map(),
|
||||||
fieldList: [],
|
fieldList: [],
|
||||||
fieldDict: new Map(),
|
fieldDict: new Map(),
|
||||||
loadingDirectory: "",
|
loadingDirectory: "",
|
||||||
|
@@ -654,17 +654,24 @@ class Macros {
|
|||||||
|
|
||||||
// Having this floating out here is sketchy, but should work out fine because the variable is always re-set
|
// Having this floating out here is sketchy, but should work out fine because the variable is always re-set
|
||||||
// through the next function before being used in defalias or undefalias
|
// through the next function before being used in defalias or undefalias
|
||||||
var aliasMap:Map<String, ReaderExpDef> = null;
|
var aliasMap:Map<String, Dynamic> = null;
|
||||||
|
var extractString = false;
|
||||||
|
|
||||||
function getAliasName(k:KissState, nameExpWithMeta:ReaderExp, formName:String):String {
|
function getAliasName(k:KissState, nameExpWithMeta:ReaderExp, formName:String):String {
|
||||||
var error = KissError.fromExp(nameExpWithMeta, 'first argument to $formName should be &call [alias] or &ident [alias]');
|
var error = KissError.fromExp(nameExpWithMeta, 'first argument to $formName should be &call [alias] or &ident [alias]');
|
||||||
var nameExp = switch (nameExpWithMeta.def) {
|
var nameExp = switch (nameExpWithMeta.def) {
|
||||||
case MetaExp("call", nameExp):
|
case MetaExp("call", nameExp):
|
||||||
|
extractString = false;
|
||||||
aliasMap = k.callAliases;
|
aliasMap = k.callAliases;
|
||||||
nameExp;
|
nameExp;
|
||||||
case MetaExp("ident", nameExp):
|
case MetaExp("ident", nameExp):
|
||||||
|
extractString = false;
|
||||||
aliasMap = k.identAliases;
|
aliasMap = k.identAliases;
|
||||||
nameExp;
|
nameExp;
|
||||||
|
case MetaExp("type", nameExp):
|
||||||
|
aliasMap = k.typeAliases;
|
||||||
|
extractString = true;
|
||||||
|
nameExp;
|
||||||
default:
|
default:
|
||||||
throw error;
|
throw error;
|
||||||
};
|
};
|
||||||
@@ -676,12 +683,21 @@ class Macros {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
k.doc("defalias", 2, 2, "(defAlias <<&call or &ident> whenItsThis> <makeItThis>)");
|
k.doc("defalias", 2, 2, "(defAlias <<&call or &ident or &type> whenItsThis> <makeItThis>)");
|
||||||
macros["defalias"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
|
macros["defalias"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
|
||||||
k.stateChanged = true;
|
k.stateChanged = true;
|
||||||
var name = getAliasName(k, exps[0], "defAlias");
|
var name = getAliasName(k, exps[0], "defAlias");
|
||||||
|
|
||||||
aliasMap[name] = exps[1].def;
|
var into = exps[1].def;
|
||||||
|
if (extractString)
|
||||||
|
aliasMap[name] = switch (into) {
|
||||||
|
case Symbol(typeName):
|
||||||
|
typeName;
|
||||||
|
default:
|
||||||
|
throw KissError.fromExp(wholeExp, "type alias must be of a plain symbol");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
aliasMap[name] = into;
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
renameAndDeprecate("defalias", "defAlias");
|
renameAndDeprecate("defalias", "defAlias");
|
||||||
@@ -774,7 +790,7 @@ class Macros {
|
|||||||
var firstValue = bindingList.shift();
|
var firstValue = bindingList.shift();
|
||||||
var b = wholeExp.expBuilder();
|
var b = wholeExp.expBuilder();
|
||||||
var firstNameSymbol = b.symbol(firstNameString);
|
var firstNameSymbol = b.symbol(firstNameString);
|
||||||
var firstNameType = Helpers.explicitTypeString(firstName);
|
var firstNameType = Helpers.explicitTypeString(firstName, k);
|
||||||
|
|
||||||
var rejectionHandlerArgsAndBody = [];
|
var rejectionHandlerArgsAndBody = [];
|
||||||
var usingDefaultHandler = false;
|
var usingDefaultHandler = false;
|
||||||
@@ -1340,7 +1356,7 @@ class Macros {
|
|||||||
var b = wholeExp.expBuilder();
|
var b = wholeExp.expBuilder();
|
||||||
var name = exps[0];
|
var name = exps[0];
|
||||||
var nameString = Prelude.symbolNameValue(name, true, false);
|
var nameString = Prelude.symbolNameValue(name, true, false);
|
||||||
var type = Helpers.explicitTypeString(name);
|
var type = Helpers.explicitTypeString(name, k);
|
||||||
var initialValue = exps[1];
|
var initialValue = exps[1];
|
||||||
var filename = if (savedVarFilename != null) {
|
var filename = if (savedVarFilename != null) {
|
||||||
if (!savedVarFilename.endsWith(".json"))
|
if (!savedVarFilename.endsWith(".json"))
|
||||||
|
@@ -359,7 +359,7 @@ class Main {
|
|||||||
v;
|
v;
|
||||||
}
|
}
|
||||||
#if macro
|
#if macro
|
||||||
var type = Context.resolveType(Helpers.parseComplexType(theInterface), Context.currentPos());
|
var type = Context.resolveType(Helpers.parseComplexType(theInterface, Kiss.defaultKissState()), Context.currentPos());
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TInst(classTypeRef, params):
|
case TInst(classTypeRef, params):
|
||||||
var classType = classTypeRef.get();
|
var classType = classTypeRef.get();
|
||||||
|
@@ -116,7 +116,7 @@ class SpecialForms {
|
|||||||
default: k.convert(args[0]).toString();
|
default: k.convert(args[0]).toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
ENew(Helpers.parseTypePath(classType, args[0]), args.slice(1).map(k.convert)).withMacroPosOf(wholeExp);
|
ENew(Helpers.parseTypePath(classType, k, args[0]), args.slice(1).map(k.convert)).withMacroPosOf(wholeExp);
|
||||||
};
|
};
|
||||||
|
|
||||||
k.doc("set", 2, 2, "(set <variable> <value>)");
|
k.doc("set", 2, 2, "(set <variable> <value>)");
|
||||||
@@ -162,7 +162,7 @@ class SpecialForms {
|
|||||||
name: varName(nameExp),
|
name: varName(nameExp),
|
||||||
type: switch (nameExp.def) {
|
type: switch (nameExp.def) {
|
||||||
case TypedExp(type, _):
|
case TypedExp(type, _):
|
||||||
Helpers.parseComplexType(type, nameExp);
|
Helpers.parseComplexType(type, k, nameExp);
|
||||||
default: null;
|
default: null;
|
||||||
},
|
},
|
||||||
isFinal: isFinal && !k.hscript,
|
isFinal: isFinal && !k.hscript,
|
||||||
@@ -456,7 +456,7 @@ class SpecialForms {
|
|||||||
};
|
};
|
||||||
if (pkg.length > 0)
|
if (pkg.length > 0)
|
||||||
type = pkg + "." + type;
|
type = pkg + "." + type;
|
||||||
ECheckType(k.convert(args[1]), Helpers.parseComplexType(type, wholeExp, !type.contains("<"))).withMacroPosOf(wholeExp);
|
ECheckType(k.convert(args[1]), Helpers.parseComplexType(type, k, wholeExp, !type.contains("<"))).withMacroPosOf(wholeExp);
|
||||||
};
|
};
|
||||||
|
|
||||||
k.doc("try", 1, null, "(try <thing> <catches...>)");
|
k.doc("try", 1, null, "(try <thing> <catches...>)");
|
||||||
@@ -479,7 +479,7 @@ class SpecialForms {
|
|||||||
},
|
},
|
||||||
type: switch (catchArgs[0].def) {
|
type: switch (catchArgs[0].def) {
|
||||||
case ListExp([{pos: _, def: TypedExp(type, _)}]):
|
case ListExp([{pos: _, def: TypedExp(type, _)}]):
|
||||||
Helpers.parseComplexType(type, catchArgs[0]);
|
Helpers.parseComplexType(type, k, catchArgs[0]);
|
||||||
default: null;
|
default: null;
|
||||||
},
|
},
|
||||||
expr: k.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))
|
||||||
@@ -539,7 +539,7 @@ class SpecialForms {
|
|||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
switch (args[1].def) {
|
switch (args[1].def) {
|
||||||
case Symbol(typePath):
|
case Symbol(typePath):
|
||||||
t = Helpers.parseComplexType(typePath, wholeExp, !typePath.contains("<"));
|
t = Helpers.parseComplexType(typePath, k, wholeExp, !typePath.contains("<"));
|
||||||
default:
|
default:
|
||||||
throw KissError.fromExp(wholeExp, 'second argument to cast should be a type path symbol');
|
throw KissError.fromExp(wholeExp, 'second argument to cast should be a type path symbol');
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user