Compare commits
3
Commits
606bf7457f
...
9701fab04a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9701fab04a | ||
|
|
913ca69e6c | ||
|
|
c0a2e0099c |
No files matched your search
@@ -61,6 +61,15 @@ that place it:
|
|||||||
order but never twice. Used by `translate` and `include`; keyword arguments are guarded by the scanner
|
order but never twice. Used by `translate` and `include`; keyword arguments are guarded by the scanner
|
||||||
instead. Grows as `Σ C(n,k)·k!` (65 for four names), which is
|
instead. Grows as `Σ C(n,k)·k!` (65 for four names), which is
|
||||||
why it is only used for signatures that name their arguments.
|
why it is only used for signatures that name their arguments.
|
||||||
|
- `wordAsValueRules(word)` / `wordAsValue($, word, continued)` — a tag's own keyword written where a value
|
||||||
|
goes. Django tells its flag from a variable by comparing the whole bit, so `reversed` is the flag of
|
||||||
|
`{% for %}` while `reversed.x` and `reversed|last` are lookups; `continued` selects that second group.
|
||||||
|
Needed because keyword extraction hands the parser the keyword wherever both it and `identifier` are
|
||||||
|
valid, so the reading in which the word names a variable has to be built back out of it. The rules are
|
||||||
|
hidden and aliased at the use site, one per level (`variable_attribute`, `value`, `filtered_value`),
|
||||||
|
because an alias renames the node its own rule makes and **cannot nest one inside another** — writing
|
||||||
|
it as nested inline `alias(alias(...))` calls silently yields a flat, partly zero-width tree that still
|
||||||
|
generates and still parses. Check the tree, not just the accept.
|
||||||
|
|
||||||
Consequences worth knowing before editing a rule:
|
Consequences worth knowing before editing a rule:
|
||||||
|
|
||||||
@@ -229,6 +238,19 @@ too if it were spelled the same way. `queries/exports.scm` names it for a tool t
|
|||||||
bind in the scope around the block, which a locals query cannot do: it places a definition in the innermost
|
bind in the scope around the block, which a locals query cannot do: it places a definition in the innermost
|
||||||
scope containing it and offers no way out again.
|
scope containing it and offers no way out again.
|
||||||
|
|
||||||
|
`queries/conditionals.scm` is data for a tool too: `@conditional.group` / `@conditional.branch` /
|
||||||
|
`@conditional.default` say which bodies render on only some passes, so a checker can tell that
|
||||||
|
`{% if a %}{% now "Y" as n %}{% endif %}{{ n }}` may reach `{{ n }}` with nothing bound. A locals query
|
||||||
|
cannot: it matches a reference to the definition whose scope contains it and has no notion of a path not
|
||||||
|
taken. A group is exhaustive iff it has a `@conditional.default`, so each pattern captures the group
|
||||||
|
alongside one of its parts and a tool needs no list of which clause belongs to which group. Adding a tag
|
||||||
|
group whose body may be skipped means adding it there — `{% cache %}` is the non-obvious one, since a
|
||||||
|
cache hit skips the body outright and `CacheNode` pushes no context.
|
||||||
|
|
||||||
|
A branch that is also a `@local.scope` confines its bindings whichever way the branch goes, which is why
|
||||||
|
`{% for %}` is inert for that check: `ForNode` renders `nodelist_empty` **inside** the same
|
||||||
|
`context.push()` as the loop body, so `empty_clause` is a scope alongside `for_clause`.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Corpus tests live in `test/corpus/*.txt`, one file per tag.
|
Corpus tests live in `test/corpus/*.txt`, one file per tag.
|
||||||
@@ -264,6 +286,12 @@ documentation or memory. Both checks are worth repeating whenever tags, filters
|
|||||||
|
|
||||||
- Django has no number token: `[\w.]+` is one lexeme and `int()`/`float()` decides whether it is a literal,
|
- Django has no number token: `[\w.]+` is one lexeme and `int()`/`float()` decides whether it is a literal,
|
||||||
so `1a`, `1e`, `0x1f`, `1.2.3`, `1__0` and `1.` are variable _lookups_ there and errors here.
|
so `1a`, `1e`, `0x1f`, `1.2.3`, `1__0` and `1.` are variable _lookups_ there and errors here.
|
||||||
|
- Django has no boolean or `None` token either. `True`, `False` and `None` are lookups, which resolve
|
||||||
|
because `BaseContext._reset_dicts` seeds every context with `{"True": True, "False": False, "None": None}`.
|
||||||
|
They are `boolean` and `none` literals here, so that a tool reading `queries/locals.scm` does not count
|
||||||
|
them as references to something the template never defines. Shadowing still parses — `{% with True=1 %}`
|
||||||
|
binds an `identifier`, because the keyword is not valid where a binding name is — but `{{ True.x }}` is
|
||||||
|
an error here and an ordinary two-part lookup in Django, which renders `string_if_invalid`.
|
||||||
- A `with` binding written twice (`{% with a=1 a=2 %}`, and the same in `{% include %}` and
|
- A `with` binding written twice (`{% with a=1 a=2 %}`, and the same in `{% include %}` and
|
||||||
`{% blocktranslate %}`) is an error here and not in Django, where `token_kwargs` builds a dict and the
|
`{% blocktranslate %}`) is an error here and not in Django, where `token_kwargs` builds a dict and the
|
||||||
later value wins. It has no use, so it is treated as the mistake it almost certainly is.
|
later value wins. It has no use, so it is treated as the mistake it almost certainly is.
|
||||||
@@ -286,11 +314,5 @@ documentation or memory. Both checks are worth repeating whenever tags, filters
|
|||||||
`{% cache 500 sidebar.name %}` names a fragment there, `{% cache 500 using="c" %}` names a fragment
|
`{% cache 500 sidebar.name %}` names a fragment there, `{% cache 500 using="c" %}` names a fragment
|
||||||
called `using="c"` rather than choosing a cache, and `{% cache 500 sidebar using= %}` takes an empty
|
called `using="c"` rather than choosing a cache, and `{% cache 500 sidebar using= %}` takes an empty
|
||||||
name. All three are errors here.
|
name. All three are errors here.
|
||||||
- `do_for` reads `reversed` off the end of the tag before it looks for `in`, so `{% for x in reversed %}`
|
|
||||||
is an error there and a loop over a variable named `reversed` here. Writing the flag as well
|
|
||||||
(`{% for x in reversed reversed %}`) is accepted by both, which is why the name is not simply reserved
|
|
||||||
in that position.
|
|
||||||
- `do_translate` refuses `as` and `noop` as the value of its `context` option, so
|
|
||||||
`{% trans "hi" context noop %}` is an error there and a context named by the variable `noop` here.
|
|
||||||
- `partial`/`partialdef` are Django builtins as of Django 6; `elif`/`else`/`empty` are modelled as parts of
|
- `partial`/`partialdef` are Django builtins as of Django 6; `elif`/`else`/`empty` are modelled as parts of
|
||||||
their enclosing tag rather than as separate tags.
|
their enclosing tag rather than as separate tags.
|
||||||
@@ -11,3 +11,28 @@ npm run parser-test # run the corpus tests in test/corpus
|
|||||||
npm run parser-build # build the WASM binary
|
npm run parser-build # build the WASM binary
|
||||||
npm run playground # interactively explore the grammar
|
npm run playground # interactively explore the grammar
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Divergences from Django
|
||||||
|
|
||||||
|
The grammar aims to accept what Django accepts, with one deliberate exception. Where Django takes an
|
||||||
|
input without complaint but the input is almost certainly a mistake — it parses, and then silently
|
||||||
|
renders nothing or quietly ignores half of what was written — the grammar reports an error instead.
|
||||||
|
Every case below is input Django itself accepts:
|
||||||
|
|
||||||
|
- **Number-shaped names.** Django has no number token: a word is a literal if `int()` or `float()` parses
|
||||||
|
it and a variable lookup otherwise, so `0x1f`, `1a`, `1.`, `1.2.3` and `1__0` look up a variable of that
|
||||||
|
name and render nothing.
|
||||||
|
- **An attribute of `True`, `False` or `None`.** Every Django context is seeded with those three names, so
|
||||||
|
`{{ True.x }}` is an ordinary two-part lookup that can never resolve.
|
||||||
|
- **A keyword argument written twice.** `{% with a=1 a=2 %}`, and the same in `{% include %}` and
|
||||||
|
`{% blocktranslate %}`, where Django builds a dict and lets the last value win.
|
||||||
|
- **Anything after a `{% static %}` path.** `StaticNode.handle_token` looks for `as` two words from the end
|
||||||
|
and ignores the rest, so `{% static "a" junk %}` and `{% static "a" as url junk %}` render as if the
|
||||||
|
extra words were not there.
|
||||||
|
- **A `{% cache %}` argument meant as something other than the fragment name.** Django takes the raw word
|
||||||
|
in that position, so `{% cache 500 using="c" %}` names a fragment called `using="c"` rather than choosing
|
||||||
|
a cache, and `{% cache 500 sidebar.name %}` names one with a dot in it.
|
||||||
|
|
||||||
|
In the other direction the grammar is more permissive only where it cannot know better: the names a
|
||||||
|
`{% load %}` brings in live in Python, so `{{ x|lenght }}` cannot be told from a filter some library
|
||||||
|
registered, and an unknown tag's arguments are assumed to have the shape `simple_tag` gives them.
|
||||||
+76
-5
@@ -64,6 +64,56 @@ function asVariable($) {
|
|||||||
return part("as", field("variable", $.identifier));
|
return part("as", field("variable", $.identifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tag's own keyword written where a value goes, with the tree an ordinary
|
||||||
|
* lookup would have so that a tool sees no difference. Where a keyword and an
|
||||||
|
* identifier are both valid, tree-sitter hands the parser the keyword, so the
|
||||||
|
* reading in which the word names a variable has to be built back out of it —
|
||||||
|
* and out of hidden rules, because an alias only renames the node its rule
|
||||||
|
* makes and cannot nest one inside another.
|
||||||
|
*
|
||||||
|
* Django tells such a keyword from a variable by comparing the whole bit, so
|
||||||
|
* "reversed" is its flag while "reversed.x" and "reversed|last" are lookups.
|
||||||
|
* That second group is what `continued` selects.
|
||||||
|
*
|
||||||
|
* @param {string} word
|
||||||
|
* @returns {Record<string, RuleBuilder<string>>}
|
||||||
|
*/
|
||||||
|
function wordAsValueRules(word) {
|
||||||
|
return {
|
||||||
|
[`_${word}_lookup`]: ($) => alias(word, $.identifier),
|
||||||
|
[`_${word}_dotted_lookup`]: ($) =>
|
||||||
|
seq(alias(word, $.identifier), ".", $.attribute),
|
||||||
|
[`_${word}_value`]: ($) =>
|
||||||
|
alias($[`_${word}_lookup`], $.variable_attribute),
|
||||||
|
[`_${word}_dotted_value`]: ($) =>
|
||||||
|
alias($[`_${word}_dotted_lookup`], $.variable_attribute),
|
||||||
|
[`_${word}_bare`]: ($) => alias($[`_${word}_value`], $.value),
|
||||||
|
[`_${word}_continued`]: ($) =>
|
||||||
|
choice(
|
||||||
|
seq(
|
||||||
|
alias($[`_${word}_dotted_value`], $.value),
|
||||||
|
optional(seq("|", $.filter_expression)),
|
||||||
|
),
|
||||||
|
seq(alias($[`_${word}_value`], $.value), "|", $.filter_expression),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rules wordAsValueRules() built, where a value goes.
|
||||||
|
* @param {GrammarSymbols<string>} $
|
||||||
|
* @param {string} word
|
||||||
|
* @param {boolean} continued whether a "." or a "|" has to follow the word
|
||||||
|
* @returns {RuleOrLiteral}
|
||||||
|
*/
|
||||||
|
function wordAsValue($, word, continued) {
|
||||||
|
return alias(
|
||||||
|
$[`_${word}_${continued ? "continued" : "bare"}`],
|
||||||
|
$.filtered_value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {RuleOrLiteral[]} chosen
|
* @param {RuleOrLiteral[]} chosen
|
||||||
* @param {RuleOrLiteral[]} rest
|
* @param {RuleOrLiteral[]} rest
|
||||||
@@ -342,7 +392,8 @@ const django = grammar({
|
|||||||
seq($.value, optional(seq("|", $.filter_expression))),
|
seq($.value, optional(seq("|", $.filter_expression))),
|
||||||
filter_expression: ($) => seq($.filter, repeat(seq("|", $.filter))),
|
filter_expression: ($) => seq($.filter, repeat(seq("|", $.filter))),
|
||||||
value: ($) => choice($.literal, $.variable_attribute),
|
value: ($) => choice($.literal, $.variable_attribute),
|
||||||
literal: ($) => choice($.number, $.string, $.translated_string),
|
literal: ($) =>
|
||||||
|
choice($.number, $.string, $.translated_string, $.boolean, $.none),
|
||||||
// digits, with single underscores allowed between them, as Python's
|
// digits, with single underscores allowed between them, as Python's
|
||||||
// int() and float() accept ("1_000") and Django's Variable relies on
|
// int() and float() accept ("1_000") and Django's Variable relies on
|
||||||
number: ($) =>
|
number: ($) =>
|
||||||
@@ -354,6 +405,12 @@ const django = grammar({
|
|||||||
* string: "_( 'a' )" is a syntax error there, not a translated literal.
|
* string: "_( 'a' )" is a syntax error there, not a translated literal.
|
||||||
*/
|
*/
|
||||||
translated_string: ($) => seq("_(", $.string, ")"),
|
translated_string: ($) => seq("_(", $.string, ")"),
|
||||||
|
// the flags of "for" and "trans", spelled as the variable names they
|
||||||
|
// also are; see wordAsValueRules()
|
||||||
|
...wordAsValueRules("reversed"),
|
||||||
|
...wordAsValueRules("noop"),
|
||||||
|
boolean: ($) => choice("True", "False"),
|
||||||
|
none: ($) => "None",
|
||||||
attribute: ($) => /[a-zA-Z0-9][a-zA-Z0-9_]*(?:\.[a-zA-Z0-9][a-zA-Z0-9_]*)*/,
|
attribute: ($) => /[a-zA-Z0-9][a-zA-Z0-9_]*(?:\.[a-zA-Z0-9][a-zA-Z0-9_]*)*/,
|
||||||
variable_attribute: ($) =>
|
variable_attribute: ($) =>
|
||||||
seq($.identifier, optional(seq(".", $.attribute))),
|
seq($.identifier, optional(seq(".", $.attribute))),
|
||||||
@@ -648,11 +705,20 @@ const django = grammar({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
part("in"),
|
part("in"),
|
||||||
part($.filtered_value),
|
// do_for reads the flag off the end and takes the sequence from the
|
||||||
// do_for reads this off the end and takes the sequence from the bit
|
// bit before it, so the flag comes last or not at all. A bare
|
||||||
// before it, so it comes last or not at all
|
// "reversed" in the sequence position leaves nothing to iterate,
|
||||||
|
// naming a sequence only when a lookup or filter continues it or
|
||||||
|
// when the flag follows it as well
|
||||||
|
choice(
|
||||||
|
seq(part($.filtered_value), optional(part("reversed"))),
|
||||||
|
seq(
|
||||||
|
part(wordAsValue($, "reversed", true)),
|
||||||
optional(part("reversed")),
|
optional(part("reversed")),
|
||||||
),
|
),
|
||||||
|
seq(part(wordAsValue($, "reversed", false)), part("reversed")),
|
||||||
|
),
|
||||||
|
),
|
||||||
optional($.template),
|
optional($.template),
|
||||||
),
|
),
|
||||||
empty_clause: ($) => seq(block("empty"), optional($.template)),
|
empty_clause: ($) => seq(block("empty"), optional($.template)),
|
||||||
@@ -811,7 +877,12 @@ const django = grammar({
|
|||||||
optional(
|
optional(
|
||||||
arrangements([
|
arrangements([
|
||||||
part("noop"),
|
part("noop"),
|
||||||
part("context", $.filtered_value),
|
// do_translate refuses "as" and "noop" as the context, comparing
|
||||||
|
// the whole bit, so a lookup that only begins with one is fine
|
||||||
|
part(
|
||||||
|
"context",
|
||||||
|
choice($.filtered_value, wordAsValue($, "noop", true)),
|
||||||
|
),
|
||||||
asVariable($),
|
asVariable($),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
; Which parts of a template render conditionally, for a tool checking that a
|
||||||
|
; variable is defined on every path that reaches a use of it.
|
||||||
|
;
|
||||||
|
; Django binds an "as" target straight into the context, and a tag that pushes
|
||||||
|
; no context leaves that binding visible after its group closes. So
|
||||||
|
;
|
||||||
|
; {% if a %}{% now "Y" as n %}{% endif %}{{ n }}
|
||||||
|
;
|
||||||
|
; renders the year when a is truthy and string_if_invalid ("" by default) when
|
||||||
|
; it is not — a silent empty string, not an error. queries/locals.scm cannot
|
||||||
|
; see that: a locals query matches a reference to the definition whose scope
|
||||||
|
; contains it and has no notion of a path that may not be taken.
|
||||||
|
;
|
||||||
|
; The halves a tool joins, by grouping matches on the @conditional.group node:
|
||||||
|
;
|
||||||
|
; @conditional.group the whole construct
|
||||||
|
; @conditional.branch one alternative; at most one of a group's branches
|
||||||
|
; renders on any given pass
|
||||||
|
; @conditional.default the branch that renders when no other one does
|
||||||
|
;
|
||||||
|
; A group is exhaustive iff one of its matches carries a @conditional.default.
|
||||||
|
; If it is not, some pass through it binds nothing, so every definition inside
|
||||||
|
; is conditional. If it is, a definition escapes only when every branch makes
|
||||||
|
; it. Each capture names both halves of the pair, so no ancestor walk is needed
|
||||||
|
; and no clause has to be attributed to a group by name.
|
||||||
|
;
|
||||||
|
; Branches nest, so the same test applies again to a group inside a branch.
|
||||||
|
;
|
||||||
|
; A branch that is also a @local.scope in queries/locals.scm confines its
|
||||||
|
; bindings whether or not it renders; the two queries compose and the scope
|
||||||
|
; decides first.
|
||||||
|
|
||||||
|
; if/elif are alternatives tested in order; else runs when none matched. None
|
||||||
|
; of the three pushes a context, so this is the case the check exists for.
|
||||||
|
(if_group
|
||||||
|
[
|
||||||
|
(if_clause)
|
||||||
|
(elif_clause)
|
||||||
|
] @conditional.branch) @conditional.group
|
||||||
|
|
||||||
|
(if_group
|
||||||
|
(else_clause) @conditional.default) @conditional.group
|
||||||
|
|
||||||
|
; ifchanged renders its body only when the watched value differs from the
|
||||||
|
; previous pass, and its else otherwise. It pushes no context either.
|
||||||
|
(ifchanged_group
|
||||||
|
(ifchanged_clause) @conditional.branch) @conditional.group
|
||||||
|
|
||||||
|
(ifchanged_group
|
||||||
|
(else_clause) @conditional.default) @conditional.group
|
||||||
|
|
||||||
|
; The loop body runs once per item and empty runs when there are none, so the
|
||||||
|
; two partition every render. Both are inside ForNode's context.push() — the
|
||||||
|
; empty branch included, which is easy to miss — so locals.scm scopes both and
|
||||||
|
; nothing escapes either way. Named here because the construct does branch, and
|
||||||
|
; because a tool reading only this file should not have to infer that it does.
|
||||||
|
(for_group
|
||||||
|
(for_clause) @conditional.branch) @conditional.group
|
||||||
|
|
||||||
|
(for_group
|
||||||
|
(empty_clause) @conditional.default) @conditional.group
|
||||||
|
|
||||||
|
; A cache body is skipped entirely on a cache hit, and CacheNode pushes no
|
||||||
|
; context, so a binding made inside it reaches the rest of the template on the
|
||||||
|
; first render and is gone on the next. One branch and no default: never
|
||||||
|
; exhaustive, which is the right answer.
|
||||||
|
(cache_group
|
||||||
|
(cache_clause) @conditional.branch) @conditional.group
|
||||||
|
|
||||||
|
; Not here, deliberately: block and partialdef bodies may also fail to render —
|
||||||
|
; a child template overrides the block, and a partial renders only where
|
||||||
|
; {% partial %} names it — but both clauses are @local.scope in locals.scm, so
|
||||||
|
; nothing they bind escapes to be checked. Bodies that always render once
|
||||||
|
; (with, filter, autoescape, spaceless, language, localize, localtime,
|
||||||
|
; timezone) are not conditional at all, and comment, verbatim and
|
||||||
|
; blocktranslate bodies hold no tags to bind anything.
|
||||||
@@ -41,6 +41,8 @@ variable: (identifier) @variable.parameter
|
|||||||
|
|
||||||
(number) @number
|
(number) @number
|
||||||
(string) @string
|
(string) @string
|
||||||
|
(boolean) @constant.builtin
|
||||||
|
(none) @constant.builtin
|
||||||
|
|
||||||
(library
|
(library
|
||||||
(identifier) @module)
|
(identifier) @module)
|
||||||
|
|||||||
@@ -11,6 +11,13 @@ variable: (identifier) @local.definition
|
|||||||
(block_clause) @local.scope
|
(block_clause) @local.scope
|
||||||
(partialdef_clause) @local.scope
|
(partialdef_clause) @local.scope
|
||||||
|
|
||||||
|
; ForNode renders nodelist_empty inside the same context.push() as the loop
|
||||||
|
; body, so "{% empty %}" is part of the loop's scope even though it is a
|
||||||
|
; separate clause: "{% for x in ys %}a{% empty %}{% now "Y" as n %}{% endfor %}{{ n }}"
|
||||||
|
; is empty. queries/conditionals.scm names both clauses as branches of the
|
||||||
|
; same group and relies on this.
|
||||||
|
(empty_clause) @local.scope
|
||||||
|
|
||||||
; blocktranslate pushes a context for its "with" and "count" bindings. Its
|
; blocktranslate pushes a context for its "with" and "count" bindings. Its
|
||||||
; asvar target is not one of them: it is written in the same tag but assigned
|
; asvar target is not one of them: it is written in the same tag but assigned
|
||||||
; outside it, and carries an "asvar" field rather than "variable" so that this
|
; outside it, and carries an "asvar" field rather than "variable" so that this
|
||||||
|
|||||||
@@ -122,6 +122,14 @@
|
|||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "translated_string"
|
"name": "translated_string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "none"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -150,6 +158,263 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"_reversed_lookup": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "reversed"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "identifier"
|
||||||
|
},
|
||||||
|
"_reversed_dotted_lookup": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "reversed"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "attribute"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_reversed_value": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_lookup"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "variable_attribute"
|
||||||
|
},
|
||||||
|
"_reversed_dotted_value": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_dotted_lookup"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "variable_attribute"
|
||||||
|
},
|
||||||
|
"_reversed_bare": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_value"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
"_reversed_continued": {
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_dotted_value"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "|"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "filter_expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_value"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "|"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "filter_expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_noop_lookup": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "noop"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "identifier"
|
||||||
|
},
|
||||||
|
"_noop_dotted_lookup": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "noop"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "attribute"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_noop_value": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_lookup"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "variable_attribute"
|
||||||
|
},
|
||||||
|
"_noop_dotted_value": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_dotted_lookup"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "variable_attribute"
|
||||||
|
},
|
||||||
|
"_noop_bare": {
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_value"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
"_noop_continued": {
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_dotted_value"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "|"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "filter_expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_value"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "|"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "filter_expression"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"boolean": {
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "True"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "False"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "None"
|
||||||
|
},
|
||||||
"attribute": {
|
"attribute": {
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[a-zA-Z0-9][a-zA-Z0-9_]*(?:\\.[a-zA-Z0-9][a-zA-Z0-9_]*)*"
|
"value": "[a-zA-Z0-9][a-zA-Z0-9_]*(?:\\.[a-zA-Z0-9][a-zA-Z0-9_]*)*"
|
||||||
@@ -3401,6 +3666,12 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
@@ -3434,6 +3705,90 @@
|
|||||||
"type": "BLANK"
|
"type": "BLANK"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "PATTERN",
|
||||||
|
"value": "[ \\t\\r\\n]+"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "PATTERN",
|
||||||
|
"value": "[ \\t\\r\\n]+"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "reversed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "PATTERN",
|
||||||
|
"value": "[ \\t\\r\\n]+"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_reversed_bare"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "PATTERN",
|
||||||
|
"value": "[ \\t\\r\\n]+"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "reversed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
@@ -6708,9 +7063,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6752,9 +7121,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6904,9 +7287,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6932,9 +7329,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6961,9 +7372,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7005,9 +7430,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7079,9 +7518,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7140,9 +7593,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7335,9 +7802,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7396,9 +7877,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7457,9 +7952,23 @@
|
|||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[ \\t\\r\\n]+"
|
"value": "[ \\t\\r\\n]+"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "filtered_value"
|
"name": "filtered_value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ALIAS",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_noop_continued"
|
||||||
|
},
|
||||||
|
"named": true,
|
||||||
|
"value": "filtered_value"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,6 +396,11 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"named": true,
|
||||||
|
"fields": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "cache_clause",
|
"type": "cache_clause",
|
||||||
"named": true,
|
"named": true,
|
||||||
@@ -1699,6 +1704,14 @@
|
|||||||
"multiple": false,
|
"multiple": false,
|
||||||
"required": true,
|
"required": true,
|
||||||
"types": [
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "none",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -2650,6 +2663,14 @@
|
|||||||
"type": ">=",
|
"type": ">=",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "False",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "True",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "_(",
|
"type": "_(",
|
||||||
"named": false
|
"named": false
|
||||||
@@ -3074,6 +3095,10 @@
|
|||||||
"type": "media",
|
"type": "media",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "none",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "noop",
|
"type": "noop",
|
||||||
"named": false
|
"named": false
|
||||||
|
|||||||
+41512
-39230
File diff suppressed because it is too large.
Load diff
@@ -455,3 +455,89 @@ For With Reversed Before In
|
|||||||
{% for x reversed in y %}a{% endfor %}
|
{% for x reversed in y %}a{% endfor %}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
==================
|
||||||
|
For Over A Variable Named Reversed
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% for x in reversed reversed %}a{% endfor %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(for_group
|
||||||
|
(for_clause
|
||||||
|
variable: (identifier)
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier))))
|
||||||
|
(template
|
||||||
|
(content))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
For Over An Attribute Of A Variable Named Reversed
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% for x in reversed.items %}a{% endfor %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(for_group
|
||||||
|
(for_clause
|
||||||
|
variable: (identifier)
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier)
|
||||||
|
(attribute))))
|
||||||
|
(template
|
||||||
|
(content))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
For Over A Filtered Variable Named Reversed
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% for x in reversed|last %}a{% endfor %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(for_group
|
||||||
|
(for_clause
|
||||||
|
variable: (identifier)
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier)))
|
||||||
|
(filter_expression
|
||||||
|
(filter)))
|
||||||
|
(template
|
||||||
|
(content))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
For With Reversed As Its Whole Sequence
|
||||||
|
:error
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% for x in reversed %}a{% endfor %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
==================
|
||||||
|
For With Reversed Three Times
|
||||||
|
:error
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% for x in reversed reversed reversed %}a{% endfor %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
@@ -488,3 +488,58 @@ Language Name Filter With An Argument
|
|||||||
{{ "de"|language_name:1 }}
|
{{ "de"|language_name:1 }}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
==================
|
||||||
|
Translate With A Context Named After Noop
|
||||||
|
:error
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% trans "hi" context noop %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
==================
|
||||||
|
Translate With A Context From An Attribute Of Noop
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% trans "hi" context noop.x %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(translate
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(string))))
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier)
|
||||||
|
(attribute)))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Translate With A Filtered Context Named After Noop
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% trans "hi" context noop|upper %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(translate
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(string))))
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier)))
|
||||||
|
(filter_expression
|
||||||
|
(filter))))
|
||||||
|
(content))
|
||||||
@@ -156,3 +156,29 @@ If Operator Adjacent To Value
|
|||||||
{% if 1and 2 %}yes{% endif %}
|
{% if 1and 2 %}yes{% endif %}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
==================
|
||||||
|
If Is Not None
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% if status is not None %}yes{% endif %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(if_group
|
||||||
|
(if_clause
|
||||||
|
(predicate
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier))))
|
||||||
|
(binaryOperator)
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(none)))))
|
||||||
|
(template
|
||||||
|
(content))))
|
||||||
|
(content))
|
||||||
@@ -361,3 +361,103 @@ Template Variable With Spaced Filter
|
|||||||
(filter_expression
|
(filter_expression
|
||||||
(filter))))
|
(filter))))
|
||||||
(content))
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Template Variable True
|
||||||
|
==================
|
||||||
|
|
||||||
|
{{ True }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(template_variable
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(boolean)))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Template Variable False
|
||||||
|
==================
|
||||||
|
|
||||||
|
{{ False }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(template_variable
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(boolean)))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Template Variable None
|
||||||
|
==================
|
||||||
|
|
||||||
|
{{ None }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(template_variable
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(none)))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Template Variable Boolean As Filter Argument
|
||||||
|
==================
|
||||||
|
|
||||||
|
{{ value|default:True }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(template_variable
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier)))
|
||||||
|
(filter_expression
|
||||||
|
(filter
|
||||||
|
argument: (value
|
||||||
|
(literal
|
||||||
|
(boolean)))))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Template Variable Name Beginning With A Literal
|
||||||
|
==================
|
||||||
|
|
||||||
|
{{ Truest }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(template_variable
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(variable_attribute
|
||||||
|
(identifier)))))
|
||||||
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Template Variable Attribute Of A Literal
|
||||||
|
:error
|
||||||
|
==================
|
||||||
|
|
||||||
|
{{ None.x }}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
@@ -111,3 +111,24 @@ With Repeating A Binding Of The Tag Before It
|
|||||||
(template
|
(template
|
||||||
(content))))
|
(content))))
|
||||||
(content))
|
(content))
|
||||||
|
|
||||||
|
==================
|
||||||
|
With A Binding Named After A Literal
|
||||||
|
==================
|
||||||
|
|
||||||
|
{% with True=1 %}a{% endwith %}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(template
|
||||||
|
(content)
|
||||||
|
(with_group
|
||||||
|
(with_clause
|
||||||
|
variable: (identifier)
|
||||||
|
(filtered_value
|
||||||
|
(value
|
||||||
|
(literal
|
||||||
|
(number))))
|
||||||
|
(template
|
||||||
|
(content))))
|
||||||
|
(content))
|
||||||
Reference in new issue
Block a user