Generable generate a single random instance
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
"description": "Generalized genetic generation for Haxe classes",
|
||||
"classPath": "src/",
|
||||
"dependencies": {
|
||||
"kiss": ""
|
||||
"kiss": "",
|
||||
"tink_macro": ""
|
||||
},
|
||||
"url": "https://github.com/NQNStudios/kisslang",
|
||||
"contributors": [
|
||||
|
@@ -2,36 +2,84 @@ package prokgen;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type;
|
||||
|
||||
using haxe.macro.ComplexTypeTools;
|
||||
using haxe.macro.TypeTools;
|
||||
|
||||
using tink.MacroApi;
|
||||
using tink.core.Outcome;
|
||||
|
||||
class Generable {
|
||||
public static macro function build():Array<Field> {
|
||||
var generatorClass:Ref<ClassType> = null;
|
||||
|
||||
function classIsGenerator(cls:ClassType) {
|
||||
if (cls == null) return false;
|
||||
if (cls.name == "Generator" && cls.pack.join(".") == "prokgen") {
|
||||
return true;
|
||||
}
|
||||
if (cls.superClass != null) {
|
||||
var scls = cls.superClass.t.get();
|
||||
if (classIsGenerator(scls)) return true;
|
||||
}
|
||||
for (iface in cls.interfaces) {
|
||||
var ref = iface.t;
|
||||
generatorClass = ref;
|
||||
var icls = ref.get();
|
||||
if (classIsGenerator(icls)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function typeIsGenerator(t:Type) {
|
||||
return classIsGenerator(t.getClass());
|
||||
}
|
||||
|
||||
function typeFromField(c:ComplexType, e:Expr) {
|
||||
if (c != null) return c.toType().sure();
|
||||
return e.typeof().sure();
|
||||
}
|
||||
|
||||
function checkFieldIsGenerator(name:String, c:ComplexType, e:Expr, generators:Map<String, Type>) {
|
||||
var t = typeFromField(c, e);
|
||||
if (typeIsGenerator(t)) {
|
||||
generators[name] = t;
|
||||
}
|
||||
}
|
||||
|
||||
var fields = Context.getBuildFields();
|
||||
|
||||
var instanceFields:Map<String, ComplexType> = [];
|
||||
var generatorFields:Map<ComplexType,String> = [];
|
||||
var instanceFields:Map<String, Type> = [];
|
||||
var generatorFields:Map<String, Type> = [];
|
||||
var generatorsByFieldType:Map<Type, String> = [];
|
||||
var hasGenScore = false;
|
||||
|
||||
var genTypes:Array<ComplexType> = [];
|
||||
|
||||
for (field in fields) {
|
||||
switch (field) {
|
||||
// TODO find all the fields that are generators
|
||||
// Find all the fields that are generators and map them by type generated
|
||||
case {
|
||||
name: name,
|
||||
doc: _,
|
||||
access: access,
|
||||
kind: FVar(type, _),
|
||||
kind: FVar(type, expr),
|
||||
pos: _,
|
||||
meta: _
|
||||
} if (access.indexOf(AStatic) != -1):
|
||||
// TODO find all fields that are non-generator instance variables
|
||||
checkFieldIsGenerator(name, type, expr, generatorFields);
|
||||
// find all fields that are uninitialized, non-generator instance variables
|
||||
case {
|
||||
name: name,
|
||||
doc: _,
|
||||
access: access,
|
||||
kind: FVar(type, _),
|
||||
kind: FVar(type, null),
|
||||
pos: _,
|
||||
meta: _
|
||||
} if (access.indexOf(AStatic) == -1):
|
||||
// TODO make sure genScore() is defined and returns Float
|
||||
instanceFields[name] = type.toType().sure();
|
||||
// make sure genScore() is defined and returns Float
|
||||
case {
|
||||
name: "genScore",
|
||||
doc: _,
|
||||
@@ -50,19 +98,62 @@ class Generable {
|
||||
}
|
||||
}
|
||||
|
||||
var useLines = [for (generator => _ in generatorFields) {
|
||||
macro $i{generator}.use(r);
|
||||
}];
|
||||
|
||||
var genLines = [];
|
||||
for (name => type in instanceFields) {
|
||||
var generatorName = if (generatorsByFieldType.exists(type)) {
|
||||
generatorsByFieldType[type];
|
||||
} else {
|
||||
for (genName => genType in generatorFields) {
|
||||
var desiredType = TInst(generatorClass, [type]);
|
||||
if (genType.unify(desiredType))
|
||||
generatorsByFieldType[type] = genName;
|
||||
}
|
||||
generatorsByFieldType[type];
|
||||
};
|
||||
if (generatorName == null) {
|
||||
throw 'No generator found for $name';
|
||||
}
|
||||
|
||||
genLines.push(macro $i{name} = $i{generatorName}.makeRandom());
|
||||
}
|
||||
|
||||
// TODO when generating fields, make sure they are handled alphabetically so seeded generation is deterministic, not dependent on Map iterator order
|
||||
var generateSpecimenField = {
|
||||
name: "_generate",
|
||||
access: [APrivate],
|
||||
kind: FFun({
|
||||
ret: null,
|
||||
args: [],
|
||||
expr: macro $b{genLines}
|
||||
}),
|
||||
pos: Context.getLocalClass().get().pos
|
||||
}
|
||||
|
||||
// TODO create a population and evolve it
|
||||
var generateField = {
|
||||
name: "generate",
|
||||
access: [AStatic, APublic],
|
||||
kind: FFun({
|
||||
ret: null,
|
||||
// TODO accept a ProkRandom arg
|
||||
args: [],
|
||||
expr: macro return 0
|
||||
args: [{
|
||||
name: "r"
|
||||
}],
|
||||
expr: macro {
|
||||
var inst = Type.createEmptyInstance(HighNumbers);
|
||||
$b{useLines}
|
||||
inst._generate();
|
||||
return inst;
|
||||
}
|
||||
}),
|
||||
pos: Context.currentPos()
|
||||
pos: Context.getLocalClass().get().pos
|
||||
};
|
||||
|
||||
fields.push(generateSpecimenField);
|
||||
fields.push(generateField);
|
||||
|
||||
return fields;
|
||||
|
@@ -8,7 +8,8 @@
|
||||
(let [:Array<Dynamic> aList (for g generators (g.makeRandom))
|
||||
:Array<Dynamic> bList (for g generators (g.makeRandom))
|
||||
:Array<Dynamic> cList (for i (range generators.length) (.combine (nth generators i) (nth aList i) (nth bList i)))]
|
||||
~aList
|
||||
~bList
|
||||
~cList)
|
||||
~(HighNumbers.generate))
|
||||
// TODO assert that no infinities or nans appear in any of the three lists, flattened:
|
||||
aList
|
||||
bList
|
||||
cList)
|
||||
~(HighNumbers.generate (new ProkRandom)))
|
||||
|
@@ -9,10 +9,14 @@ class HighNumbers {
|
||||
var iList:Array<Int>;
|
||||
var fList:Array<Float>;
|
||||
|
||||
static var iGen:IntGen = new IntGen(-1000, 1000);
|
||||
static var fGen:FloatGen = new FloatGen(-1000, 100);
|
||||
static var iListGen:ArrayGen<Int> = new ArrayGen<Int>(new IntGen(-1000, 1000), 0, 10);
|
||||
static var fListGen:ArrayGen<Float> = new ArrayGen<Float>(new FloatGen(-1000, 1000), 0, 10);
|
||||
static var iGen = new IntGen(-1000, 1000);
|
||||
static var fGen = new FloatGen(-1000, 100);
|
||||
static var iListGen = new ArrayGen<Int>(new IntGen(-1000, 1000), 0, 10);
|
||||
static var fListGen = new ArrayGen<Float>(new FloatGen(-1000, 1000), 0, 10);
|
||||
|
||||
function toString() {
|
||||
return '$i $f $iList $fList';
|
||||
}
|
||||
|
||||
function genScore() {
|
||||
var sum:Float = i + f;
|
||||
|
Reference in New Issue
Block a user