antlrcs
antlrcs copied to clipboard
Separator output bug
When iterating over a list, separators for items skipped at the beginning of a list are not output, but once an item in the list is output, separators are output for subsequent items, even when items are skipped. The following C# code illustrates this. The output is: "2 is even," (note the trailing comma separator, but there isn't a comma before the 2, for the first skipped item)
static void Main (string [] args)
{
List <Item> items = new List <Item> () { new Item ("1", false), new Item ("2", true), new Item ("3",false)};
string string_template_group =
@"
even_params (parameters) ::=
<<
<parameters:{p|<if (p.is_even)><p.value> is even<endif>}; separator = "", "">
>>
";
TemplateGroup group = new TemplateGroupString (string_template_group);
Template even_params = group.GetInstanceOf ("even_params");
even_params.Add ("parameters", items);
Console.WriteLine (even_params.Render ());
} // End Main
class Item
{
public string value { get; set; }
public bool is_even { get; set; }
public Item (string V, bool E)
{
value = V;
is_even = E;
}
} // End class Item
Hi Brian,
I am no expert, but in your template, the odd parameters are not skipped per say, you simply don't output anything when treating them.
Considering that it has treated said parameter (even by not printing anything), string template logically adds a separator.
As ways to obtain what you are looking for, you could filter out items by adding a .where(i => i.isEven)
LINQ call to items when adding them to the template ?
The template can then become the dead simple
<parameters;separator= "", "">
Another possibility that I see is to use two templates combined with the use of first()
and rest()
functions
You print the first element without a comma and then call another template:
$if(first($parameters).isEven)$$first($parameters).value$ is even$endif$$PrintFollowers(rest(parameters))$
In PrintFollowers you simply add the comma directly to each even parameter print.
Please notice that I am using slightly modified attribute names in the code above and '$' as delimiters 😅 .
Also I would suggest making the Value parameter as an int
and compute isEven
with a modulo for easier testing 😉
I hope this helps. Kind regards.
Thank you for your response @chaami
If what you say is true, then there should have been a separator between all items in the list, but there isn't; however, notice that there aren't separators for items not output for items at the beginning of the list, but once an item is output (in my example, the second item), then ST outputs a separator for every subsequent item. So, clearly ST knows that it shouldn't be outputting separators at the beginning of the list, but once it does output an item it forgot to suppress separators for items not output.
I hadn’t thought about using LINQ for filtering. Thank you for that!
Hi @BrianCatlin, Oups, actually the second workaround that I have given you missing the case when the first member is odd ! Complete solution:
<if(first(parameters).isEven)><first(parameters).value> is even<PrintFollowers(rest(parameters))>
<else><even_params(rest(parameters))><endif>
Actually if print the length of the list with
<length(parameters:{p|<if (p.is_even)><p.value> is even<endif>})>
Should yield to 3.
My guess is that StringTemplate handles gracefully empty first elements of lists and then you are on your own 😉
strip()
unfortunately only remove null
values...
I haven't found a way to push a null in a list through templates (only by specifically adding null in the c# Add call).
Thanks!
Glad I could help... It helped me dig a little deeper into StringTemplate 😉 Good luck !