To be very succinct about it: - You're trying to make sections and substitutions the same by defining common expressions, which include formatters. But sections and substitutions are not the same.
- However, the *values* of both sections and substitutions *are* the same in my model (strings), and thus formatters and predicates can apply to both. thanks, Andy On Sat, Jun 20, 2009 at 12:48 PM, Andy Chu<[email protected]> wrote: > OK interesting. I see what you mean more clearly with the single > definition of expressions. Either a simple name or a > name|formatter|... chain is an expression, and you just keep the > existing rule which determines whether to show a section. > > But there's a problem as you've defined it: sections can't contain > .name lookups now. Even if they could, the lookup is "direct", not > the type that walks the stack. The fundamental problem is that for a > section, you're looking for context to test for truth and push on the > stack, while in a substitution, you're looking for a value to put in > the output. These just can't be made the same. > >> An expression has the form name ("|" name)*. >> To evaluate the expression, the leading name is looked up >> in the value stack (same as current JSON template) to produce >> an initial value. Then each .name is applied, replacing the value >> with the result of looking that name up in value, which must >> be a JSON map. Then each |name is applied, replacing >> the value with the result if applying the named filter to the value. >> The expression a|b|c|d would be written d(c(b(a))) in many >> programming languages. The special leading name "@" means >> the top element on the value stack. > > As mentioned, we would need 2 types of expressions here. In my > formulation, there are separate but similar syntaxes for substitutions > and sections, and then the formatters apply to *values*. You haven't > defined the value of a section here -- only the value of an > expression, which may appear inside a section directive. > > So it looks like you're punting on the formatters on (expanded value > of) sections. But I think this is just too useful to pass up. > >> A section has the form >> "{.section" expr "}" true-body ("{.or}" false-body)? "{.end}" >> In the output, it is replaced by the result of the following procedure. >> First, expr is evaluated to produce a value v. >> If v is not false or empty, v is pushed on the value stack, true-body >> is executed, and v is popped off. Otherwise, false-body is executed >> if present. > > The asymmetry here will lead to awkwardness in practice. Say you have > {"num": 3}, then the most compact thing to do is: > > > {.section num|plural?) > There are {...@} people here. > {.or} > There is {num} person here. > {.end} > > Of course you can use {num} in the first clause because of the stack > walk, but this subtlety is confusing. > > In my formulation, we retain the original rule that the "num" context > is pushed on the stack if it's non-empty. The predicate determines > which one to execute. These decisions would be orthogonal -- in yours > they're tied together because you discard the original value in favor > of the filtered one. > > Also, the definition for plural? here is: > > def Plural(num): > if num > 1: > return num > else: > return None > > I'd rather write: > > def Plural(num): > return num > 1 > > >> A repeated section has the form >> "{.repeated section" expr "}" body ("{.or}" false-body)? "{.end}" >> [Yes there's also an alternates-with but it doesn't matter here.] >> In the output, it is replaced by the result of the following procedure. >> First, expr is evaluated to produce a value v, which must be an array. >> For each element of v, that element is pushed on the stack, body is >> executed, and the element is popped off. If v is empty, false-body >> is executed if present. >> >> As a result of this definition, one style of filters is as "predicates" >> which return either their input or false. Using them can enable or >> disable sections appropriately: >> >> {.section num|>1} >> There are {num|english} people in group {name} >> {.or} >> {.section num|==1} >> There is one person in group {name} >> {.or} >> There are no people on group {name}. How sad. >> {.end} >> {.end} > > This brings up something I've been thinking about -- chaining of > conditions (e.g. elif, elsif). I would rather have a flat structure > than a nested one. > >> It is also possible to use filters to transform the data before iterating >> over it, for example to select only the public fields from a data structure >> definition: >> >> {.repeated section fields|public?} >> Field {name} has type {type}. >> {.end} > > Right. In either formulation, I would write that like this, to avoid > using a loop in the formatter: > > {.repeated section fields} > {section @|public?} {# Repeated sections move the cursor each time} > Field {name} has type {type}. > {.end} > {.end} > > public? operates on an element rather than a list of elements. > >> Or to order an array in a certain way: >> >> {.repeated section people|sort-by-phone-number} >> {name} {phone-number} >> {.end} > > Unrelated to this discussion -- in either formulation, you can have > > {.repeated section people|sort phone-number} > {name} {phone-number} > {.end} > > {.repeated section people|sort name} > {name} {phone-number} > {.end} > > Where sort is a single formatter that takes a string argument. This > works like the template-file ("include" feature) if you haven't seen > it. > > ---- > > About overloading | operator -- note that I tried to use ? as an > operator instead of |. However, this just looks ugly: > > {.section ? plural} > {.end} > > {var?plural} > > The ? reads better after the predicate name, and it also would look > too much like a ternary operator, but the position of the predicate > swapped. > > I'm open to suggestions on syntax that distinguishes predicates from > formatters. Formatters can be chained, so | is appropriate, but > predicates so far can't, although it's conceivable to have multiple > predicates. > >> Or perhaps to create a potentially large data structure on the fly: >> >> {.section x|primes-up-to-10000} >> {...@} is prime. >> {.end} >> Again, the primes are: {x|primes-up-to-10000}. >> >> In this implementation, evaluation of expressions has just >> one behavior: a|b|c|d means take a, pipe it through b, c, and d, >> and use the result as the value of the expression, no matter >> what the context. >> >> Neither sections nor substitutions have predicates or formatters. >> Data has filters. Instead of 4 cases, there is 1. >> Predicates are an idiom, not a built-in concept. > > So, as mentioned, you do have 2 cases for expressions. And my > formulation has 2 as well -- this is because I've introduced the > concept of "values" of sections and formatters, and defined > predicates/formatters on values, not a 2x2 matrix. > > In the end I think that the practical matter of formatting sections is > vital. This was asked for by users, and it will fix nastiness I have > in my doc/makedocs.py stuff. There will be a bunch of silly Python > code eliminated in favor of simple, declarative templates. > > It's very interesting how there can be two consistent but different > interpretations of the same language. I'm glad that coherent models > can be made. > > thanks, > Andy > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "JSON Template" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/json-template?hl=en -~----------~----~----~----~------~----~------~--~---
