[stringtemplate-interest] Why an == operator is sometimes necessary, and how to implement it (ST3/C#)
Terence Parr
parrt at cs.usfca.edu
Tue Mar 23 14:26:58 PDT 2010
Hi Harald, it still seems to me that deciding what replacements to do is part of the model not the view. I encapsulate the translation rules primarily in the model unless they are fixed one-to-one mappings, in which case I can do a static map in the template group file. personally, I figure out what to generate and then ask ST to dump it out in the right format.
Ter
On Mar 12, 2010, at 11:15 AM, Harald Mueller wrote:
> Hi -
>
> as we all know, ST does not have any expression operators in its language, and that is almost always a good thing. However, in a well-worn code generator we use to create triggers in an SQL database, we finally got to the point where we needed an equals operator in $if(...)$. Here is why; and how we implemented it.
>
> The problem is as follows: Input to the generation is (a) a list of SQL tables; (b) the FROM part of an SQL statement, which is a tree of join nodes; each join node points to a table (and of course has information about the joined columns and inner/outer etc., but that's not important); and (c) a replacement string (typically "INSERTED" or "DELETED"; but there are more).
> The job to do is to write a trigger for each table in the join tree, such that the table itself is replaced with the replacement string.
>
> A small example:
> (a) T1, T2
> (b) ... FROM T1 INNER JOIN T2 INNER JOIN T3
> (c) "INSERTED"
> Result:
> ... FROM INSERTED INNER JOIN T2 INNER JOIN T3
> ... FROM T1 INNER JOIN INSERTED INNER JOIN T3
>
> The example below is a simplified version of the above, however, its ST template marks nodes in a tree with an arrow (<--) if the node's "table name" is equal to the "replacement table".
>
> Here is the model, together with the "equals operator":
>
> public class Table {
> public string Name;
> }
>
> public class Join {
> public readonly string Name;
> public readonly Table JoinedTable;
> public readonly List<Join> Children;
> public Join(string name, Table joinedTable, params Join[] children) {
> Name = name;
> JoinedTable = joinedTable;
> Children = new List<Join>(children);
> }
> }
>
> Here are the templates - first the Main template, then the recursive one for printing the tree.
>
> Main(Target, Tables) ::= <<
> $Tables:PrintTreeReplacingTable(Target=Target,Replace=it)$
>>>
>
> PrintTreeReplacingTable(Target,Replace) ::= <<
> $Target.Name$ $if(Target.NameIsReplace.(Replace.Name))$ <-- $endif$
> $Target.Children:PrintTreeReplacingTable(Target=it,Replace=Replace)$
>
>>>
>
> The important idea here is the expression
>
> Target.NameIsReplace.(Replace.Name)
>
> where .NameEquals is a property that returns an IDictionary. The (Replacement.Name) then passes in a value which is in effect the parameter of a single-arg function which implements "Target.Name == Replace.Name" - that's the whole trick.
>
> So we extend Join with the following additional property
>
> public IDictionary NameEquals {
> get {
> return new Equals(JoinedTable.Name);
> }
> }
>
> and the class Equals, which is implemented as follows:
>
> class Equals : DictionaryBase, IDictionary {
> private readonly string _tn;
>
> public Equals(string tn) {
> _tn = tn;
> }
>
> bool IDictionary.Contains(object key) {
> return key.ToString() == _tn;
> }
>
> object IDictionary.this[object key] {
> get {
> return key.ToString() == _tn;
> }
> set { throw new NotImplementedException(); }
> }
> }
>
> That's it. Maybe it helps someone.
> And maybe someone's got an idea how this works without that IDictionary trick - but we didn't see how!
>
> Regards
> Harald M.
>
> --
> GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT!
> Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01
> _______________________________________________
> stringtemplate-interest mailing list
> stringtemplate-interest at antlr.org
> http://www.antlr.org/mailman/listinfo/stringtemplate-interest
More information about the stringtemplate-interest
mailing list