Yesterday we were debating what Boolean && and || do to the complexity of templates. My feeling is still that this works to reduce template complexity without compromising the model/view separation. I often find myself with nested ifs that would be consolidated if I had those operators.
Similarly, I wonder if this could not be expanded with a few other constructs that are similarly oriented towards choice/configuration. Can we have a limited form of switch or do we fall off the end of the map and the model should pick out a template beforehand. The latter I guess, but does the ensuing complexity of many templates end up defeating the purpose of MV separation? Jim > -----Original Message----- > From: [email protected] [mailto:[email protected]] > On Behalf Of Kay Röpke > Sent: Friday, April 23, 2010 4:12 AM > To: Terence Parr > Cc: ANTLR-dev Dev > Subject: Re: [antlr-dev] v4 code gen > > hi! > > On Apr 23, 2010, at 2:59 AM, Terence Parr wrote: > > > hi, started thinking about it... > > > > http://www.antlr.org/wiki/display/~admin/v4+code+generation > > > while i totally agree with the goal to reduce the number of templates > nested conditionals get messy, too. > recently i wrote a relatively simple codegenerator for a custom google > protobuf implementation, here's one of the simpler templates: > > buildProtobuf(field, names) ::= << > <if(field.transient)><! this field is computed from some other > field(s), skip it in the merge code !> // <field;format="variableName"> > is transient, no sense in serializing it. > <else> > <if(field.repeated)> > // TODO serialize repeated fields properly, depends on the field type: > native types are fine (even if boxed), message types are not fine at > all. > <else> > <if(field.messageType)> > <! message type, we should not follow asset links !> if > (has<field;format="methodName">) { > <names.outerClassName>.<field; format="shortTypeName">.Builder > <field;format="variableName">Builder = <names.outerClassName>.<field; > format="shortTypeName">.newBuilder(); > > < > field > ;format > ="variableName">Builder.setId(get<field;format="methodName">().getId()) > ; > > b.set<field;format="methodName">(<field;format="variableName">Builder); > } > <else> > <! plain native type just call protobuf builder !> if > (has<field;format="methodName">) { > > b.set<field;format="methodName">(get<field;format="methodName">()); > } > <endif> > <endif> > <endif> > >> > > as you can see, there are only three conditions, but even those make it > icky to follow already. other parts of the template group are even > worse, and antlr seems to have even more branches in its codegen. > now, having the multiple templates is not ideal either. > part of the problem stems from not being able to tell which template > applies in which circumstance. > in the past i've tried to model templates after classes or methods, > having one template for each variant of the template output, much like > antlr does it today (although the division in the code isn't as clear > in antlr3 today). > what i've noticed in that approach is that there are often large chunks > of text that are common between multiple templates. the next step was > to factor those common parts out, but unfortunately that usually made > it almost incomprehensible, too, not to mention that it very closely > ties the template structure to the code structure. but that's only > going to be a problem if one can anticipate major refactorings in the > code. we can probably ignore that because antlrs code generator is > likely to be pretty stable over time. > > i've also noticed that proliferation of setAttribute() calls makes it > much much harder to follow what's going on, totally agree with passing > in sensible objects. > most of the time i'm passing in the model objects directly, once in a > while i'm wrapping several model objects in "view controller" objects, > just to be able to access related data in the templates without > requiring me to change my model. > > perhaps a sensible approach would be to have a hierarchy of "token ref > representation" classes, which get instantiated depending on the > context of that token reference (that would be some decision in a tree > walker, i guess). > otoh, that would be a 1-to-1 relationship with the number of templates > again :( but effectively most of the tokenref templates already are > factored out a lot, referring to one another and other common elements > like listLabel. > > i think that just by introducing some representation classes the > templates would become much simpler, for example take the various > matching templates like lexerStringRef, wildcard et al: > they all have an <if(label)>...<endif> clause. by passing in a label > representation object, instead of the label string, that could collapse > down to <label>, pushing some of the logic back into the code > generator. > it's entirely feasible to have a "null label" that expands to the empty > string, if there is no label. > i guess that once you start looking for ifs many of them are actually > of this kind. > another example: wildcardChar vs wildcardCharListLabel. the latter is a > superset of the former, but now you have two templates instead of one, > instead of always assuming there is a listlabel, even if that might be > the null listlabel. > > probably i've been chasing templace invocation chains for too long ;) > btw, the example i pasted above used template invocations for the > various cases before, rendering it completely unreadable over time. > that kind of invalidates my point, because i've gone back to the ifs, > but i guess that just illustrates that it is a thin line. > > cheers, > -k > -- > Kay Röpke _______________________________________________ antlr-dev mailing list [email protected] http://www.antlr.org/mailman/listinfo/antlr-dev
