Inject new field through DSL
brian
16 Jun 2012
It looks like you are not actually adding the field to the type definition. Try adding a line like this:
parent.addSlot(f)
ystrot
16 Jun 2012
I do. There is one from the bottom line of InjectFieldPlugin.compile.
brian
16 Jun 2012
Actually I don't understand what the problem is. You are saying reflection works for getting/setting the field. The problem is the initialization of the field in the constructor? That happens in Normalize step by running thru all the fields and adding init statements into your constructor.
ystrot
17 Jun 2012
Oh, I see. DSL parsing happens in the ResolveExpr step which appears after Normalize step. I just added constructor initialization into my DSL plugin and it works correctly now. Thanks for help!
ystrot
16 Jun 2012
I'm playing with Fantom DSL for a while. However I have a problem with injecting custom field to a type where DSL was declared. There is a test I have:
class InjectFieldTest : Test { Str inject := InjectField<||> Void test1() { verifyNotNull(field) } Void test2() { field.set(this, "a") verifyEq("a", field.get(this)) } Void test3() { verifyEq("", field.get(this)) } private Field? field() { typeof.field("name") } }As you can see
InjectField<||>should injectStr name := "". But something goes wrong:test1passed. So new field was generated.test2passed. So I can set value to the field and get it.test3failed.field.get(this)return null.My DSL plugin:
class InjectFieldPlugin : DslPlugin { new make(Compiler c) : super(c) {} override Expr compile(DslExpr dsl) { loc := dsl.loc parent := types.find { it.loc.file == loc.file } type := ns.resolveType("sys::Str") f := FieldDef(loc, parent, "name") f.flags = FConst.Public f.fieldType = TypeRef(loc, type) f.init = LiteralExpr.makeStr(loc, ns, "") //generate synthetic getter/setter defGet(f) defSet(f) f.flags += FConst.Storage parent.addSlot(f) return LiteralExpr.makeStr(dsl.loc, ns, "") } ... }I initialized custom field with an empty string
f.init = LiteralExpr.makeStr(loc, ns, ""). Without this line I will getNon-nullable field name must be assigned in constructor makeas expected. But for some reason initialized field returns null. Am I missed something or is it a bug?There is full source I used: https://bitbucket.org/ystrot/play/src/8190f89645b4/fan/InjectFieldPlugin.fan