Thanks Daniel for your feedback. See my answers below Am So., 11. Nov. 2018 um 19:14 Uhr schrieb Daniel Dekany <[email protected] >:
> Sunday, November 11, 2018, 11:40:50 AM, Christoph Rüger wrote: > > > Am So., 11. Nov. 2018 um 09:25 Uhr schrieb Daniel Dekany < > [email protected] > >>: > > > >> Saturday, November 10, 2018, 3:08:14 PM, Denis Bredelet wrote: > >> > >> > Hi, > >> > > >> > Le 9 novembre 2018 à 22:36, Christoph Rüger <[email protected]> a > >> écrit : > >> > > >> > Am Fr., 9. Nov. 2018 um 22:55 Uhr schrieb Daniel Dekany < > >> [email protected] > >> > : > >> > > >> > It's certainly tricky, but as far as I see possible (but then, who > >> > > >> > knows what will one find when actually working on it). It's also a > >> > feature missing a lot. It's especially missing for #list (I know that > >> > you need it for something else), because if you filter the items > >> > inside #list with #if-s, then #sep, ?hasNext, etc. will not be usable. > >> > > >> > Let me say that I disagree here. > >> > > >> > I do not think that closures are required for FreeMarker, nor that > they > >> are a good idea. > >> > > >> > If we add new features to the FreeMarker *tempate engine* I would > >> > rather we focus on multi-part macro body rather than an advanced > >> language feature like closures. > >> > > >> > You can add ?filter and ?map if you want, a simple expression as > >> parameter should be enough. > >> > >> Yes, as I said, we certainly start with only allowing lambdas in > >> ?filter/?map, also certainly in ?contains. > >> > > Would be enough in my opinion and very useful. > > > > Is it possiblefor you to give some pointers to the code on how this could > > be implemented? I would maybe like to wrap my head around this a little > bit. > > Please feel yourself encouraged! (: > > > I started looking at seq_containsBI ( > > > https://github.com/apache/freemarker/blob/a03a1473b65d9819674b285a0538fed824f37478/src/main/java/freemarker/core/BuiltInsForSequences.java#L291 > ) > > and > > and reverseBI ( > > > https://github.com/apache/freemarker/blob/a03a1473b65d9819674b285a0538fed824f37478/src/main/java/freemarker/core/BuiltInsForSequences.java#L264 > ) > > just to find something related (seq_containsBI checks something) and > > reverseBI returns a new sequence. > > What I haven't found is a function which takes an Expression as a > > parameter. > > Is there something similar already or would that be a new thing? > > It's a new thing in that it will be part of the expression syntax > (even if for now we will only allow lambdas as the parameters of a few > built-ins, so that we can get away without closures). So it's a new > Expression subclass, and has to be part of the parser (ftl.jj) as > well. Hmm, that parser stuff is new for me, it'll take me some time to get into it. > As of lazy evaluation of parameters expressions, that's already > done in the built-ins in BuiltInsWithParseTimeParameters, and you will > see it's trivial to do, but the situation there is much simpler. > > > In principle, a LambdaExpression should evaluate to a > TemplateMethodModelEx, and then you pass that TemplateMethodModelEx to > the called built-in or whatever it is. But with the approach of > BuiltInsWithParseTimeParameters we can certainly even skip that, and > just bind to the LambdaExpression directly, add a LocalContext that > contains the lambda arguments, end evaluate the LambdaExpression right > there, in the built-in implementation. Or at least at a very quick > glance I think so. > Not sure I can follow completely but that hint with* BuiltInsWithParseTimeParameters* got me started, but at the moment I'm stuck as I need to get more familiar with the internals of Freemarker. I am also not sure I am on the same page regarding the syntax we are aiming for and why I would need to extend the parser when there is something like BuiltInsWithParseTimeParameters.... Here is an example what I have in mind: I started with the ?filter() builtin. I had a syntax like this in mind: *Example 1: ["a","b","c"]?filter(element, element == "c")* *Example 2: ["a","b","c"]?filter(element, element == someOtherVariable, someOtherVariable="c")* Not sure if that's what you have in mind too, but to me it made sense with regards to BuiltInsWithParseTimeParameters and I could start without touching parser stuff. *1st argument 'element'* would just be the iterator variable similar to <#list ["a","b","c"] as *element*> 2nd argument is the filter lambda expression... aka our filter condition 3rd+n argument are optional parameters in case used in the lambda expression So at first I was looking how <#list> works and found IteratorBlock, and though I could reuse it somehow. Here is some simple pseudo code I played around for the for Example 1: static class filter_BI extends BuiltInWithParseTimeParameters { TemplateModel _eval(Environment env) throws TemplateException { // sequence TemplateModel targetValue = target.evalToNonMissing(env); List parameters = this.parameters; Expression iteratorAlias = (Expression) parameters.get(0); Expression conditionExpression = (Expression) parameters.get(1); TemplateSequenceModel seq = (TemplateSequenceModel) target.eval (env); for (int i = 0; i < seq.size(); i++) { TemplateModel cur = seq.get(i); // this is where I am stuck at the moment // I basically want to evaluate conditionExpression where iteratorAlias is basically what I passed as 'element' // I am not sure if or how LocalContext could come into play here // basically for each iteration I would assign the current loop element to a context variable with the name 'element' // and then evaluate conditionExpression with that context. // if conditionExpression is "true" then I would populate add the current sequence element 'cur' // to a new result-List.... and return that.... something // I wanted to reuse IteratorBlock here somehow, but didn't get it to work yet. // maybe this is a stupid idea, or we just need something similar } } Ok so far for my pseudo code.... Maybe you could give some more pointers based on that... in case this makes any sense ... Another similarity to BuiltInsWithParseTimeParameters is that we won't > allow separating the `?someBI` and `(arg)`. Like, with the example of > `cond?then(1, 2)`, you aren't allowed to do this: > > <#assign t=cond?then> > ${t(1, 2)} > > That maybe looks natural, but most other built-ins allow that. Of > course we can't allow that for ?filter etc., because then we need > closures again. > > >> Multi-part macro body is also planned. Means, I know it definitely > >> should be added, but who knows when that's done... I mean, it's like > >> that for what, a decade? (: It's not even decided what it exactly > >> does, as there are many ways of approaching this. (I have my own idea > >> about what the right compromise would be, but others has other > >> ideas...) > >> > >> Filtering lists bothers me because the template language should be > >> (and somewhat indeed is) specialized on listing things on fancy ways > >> that used to come up when generating document-like output. (If it > >> doesn't do things like that, you might as well use a general purpose > >> language.) Thus, that filter is unsolved (filtering with #if is > >> verbose and spoils #sep etc.) bothers me a lot. > >> > >> BTW, ?filter and ?map is also especially handy in our case as > >> FreeMarker doesn't support building new sequences (sequences are > >> immutable). Although it has sequence concatenation with `+`, it's not > >> good for building a sequence one by one, unless the sequence will be > >> quite short. > >> > > Good point. > > > > > >> > >> > Cheers, > >> > -- Denis. > >> > >> -- > >> Thanks, > >> Daniel Dekany > >> > >> > > > > -- > Thanks, > Daniel Dekany > > Thanks Christoph -- Synesty GmbH Moritz-von-Rohr-Str. 1a 07745 Jena Tel.: +49 3641 5596493Fax.: +49 3641 5596499 Internet: https://synesty.com <https://synesty.com> Geschäftsführer: Christoph Rüger Unternehmenssitz: Jena Handelsregister B beim Amtsgericht: Jena Handelsregister-Nummer: HRB 508766 Ust-IdNr.: DE287564982
