add unexpected argument error

This commit is contained in:
danhanson committed 2026-09-14 17:51:45 -05:00
1 parent 5f66027dcf
commit f17fdd2d74
19 files changed
+48375 -31371

No files matched your search

+25 -7
View File
@@ -197,13 +197,30 @@ group can hold it — `{% endif %}` with nothing open, `{% else %}` in a `{% for
and error recovery placed it badly: every tag starts with `{%` and the read token, which the parser has
already accepted when the name turns out to be wrong, so recovery rewinds to just after them and folds the
stray tag into whichever tag comes next, which then holds the `ERROR`. `unexpected_tag` takes any of
`NAMES_INSIDE_A_TAG_GROUP` with loose arguments, so there is nothing to recover; `prec.dynamic(-1)` keeps it
`NAMES_INSIDE_A_TAG_GROUP` with loose arguments, so there is nothing to recover; `prec.dynamic(-2)`, or `-4`, keeps it
from displacing a tag the group does take, and `queries/errors.scm` reports it as
`@error.unexpected_tag`. It added 31 states and no `conflicts` entry.
**Words a tag does not take are an `unexpected_argument` inside it.** Every close utility accepts one
before its scanner token, so `{% else x %}` stays the `else` of its group, `{% endif junk %}` still closes
its `if` (it used to leave the whole file an `ERROR`), and `{% static "a.css" "b.css" %}` is a `static_tag`.
Each word is `token(prec(-1, /[^\s%]+/))`: tree-sitter weighs lexical precedence before match length, so a
token an argument really takes wins wherever one is valid (`b|upper` stays a filtered value) and a loose
word only matches where nothing else can. The node costs -1 of dynamic precedence, which is why
`unexpected_tag` costs -2 or -4: a misused tag its group does take has to beat reading it as a stray.
A separator after any argument can now also start stray words, so it needs `conflicts` entries for
`unexpected_argument`, `predicate` and `_translate_option`, and it took the table from 3,363 states to
4,894 and the Wasm build from 251KB to 319KB.
Two consequences. A repeat the scanner refuses — `{% with a=1 a=2 %}`, `{% blocktrans trimmed trimmed %}`
— is reported as an unexpected argument rather than an `ERROR`. And where a keyword is valid after the
arguments (`reversed`, `as`, `only`), a stray word shaped like an identifier is still an `ERROR`:
`{% for a in b zqx %}` puts it on `b`, most likely because keyword extraction lexes `zqx` as an
`identifier`, which is not valid there, before the loose-word token is considered.
Where several tags share a name the group holds only once — `{% if %}{% else %}{% else %}{% else %}` — reading
any of them as the stray parses, so the ties are broken by dynamic precedence: `unexpected_tag` is -1 when
`_group_held` confirms the innermost group already holds the name and -2 otherwise, so each tag flagged
any of them as the stray parses, so the ties are broken by dynamic precedence: `unexpected_tag` is -2 when
`_group_held` confirms the innermost group already holds the name and -4 otherwise, so each tag flagged
before its time costs one more, and the first still opens the block however many follow.
**Builtin names must stay keyword-extractable, or the fallbacks swallow them.** `word: $.identifier` turns
@@ -368,7 +385,8 @@ A branch that is also a `@local.scope` confines its bindings whichever way the b
`context.push()` as the loop body, so `empty_block` is a scope alongside `for_block`.
`queries/errors.scm` collects what an editor should report: `(ERROR)` as `@error.syntax`, `(MISSING)` as
`@error.missing`, and every missing-tag marker as `@error.missing_tag`. A tree holding only markers has
`@error.missing`, every missing-tag marker as `@error.missing_tag`, and `unexpected_tag` and
`unexpected_argument` as `@error.unexpected_tag` and `@error.unexpected_argument`. A tree holding only markers has
no `has_error`, so a tool that checks that flag alone misses them. Adding a tag group means adding its
marker there, since no supertype matches them all.
@@ -423,8 +441,8 @@ unavoidable limitation, or a case where this grammar is the more permissive one
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
`{% 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.
`{% blocktranslate %}`) is reported here, as an `unexpected_argument`, 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.
- `{% csp_nonce_attr "a" media="b" %}` is accepted, matching Django, which only rejects it at render time.
- A misspelled tag or filter cannot be caught: `{{ x|lenght }}` is indistinguishable from a filter some
library registered. Cross-referencing names against `{% load %}` needs the project's Python, so it
@@ -437,7 +455,7 @@ unavoidable limitation, or a case where this grammar is the more permissive one
redefines `length` with a different arity gets a false error here.
- Django's `static` tags ignore what follows their argument: `StaticNode.handle_token` looks for `as` two
bits from the end, so `{% static "a" junk %}` and `{% static "a" as u v %}` are accepted there and
rejected here, and `PrefixNode.handle_token` raises `IndexError` rather than `TemplateSyntaxError` on
reported here as an `unexpected_argument`, and `PrefixNode.handle_token` raises `IndexError` rather than `TemplateSyntaxError` on
`{% get_static_prefix as %}`.
- Django's `{% cache %}` takes its fragment name as the raw word in that position and finds the cache to
use by testing whether the last word starts with `using=`, and only when something precedes it. So
+5 -2
View File
@@ -69,7 +69,8 @@ Five of the files in `queries/` are query files an editor loads:
it. A marker is placed only where the scanner can tell: at the end of input, before an end tag that
belongs to an enclosing group, or before an `{% endblock %}` naming a block further out.
A group's tag written where no open group can hold it, such as `{% else %}` inside a `{% for %}`, is an
`unexpected_tag`, captured as `@error.unexpected_tag`.
`unexpected_tag`, captured as `@error.unexpected_tag`. Words a tag does not take, such as the `x` in
`{% else x %}`, are an `unexpected_argument` inside that tag, captured as `@error.unexpected_argument`.
The other three are data for a tool rather than queries an editor runs. Each captures the two halves of a
relation a tree-sitter query cannot express, and the tool does the join:
@@ -224,7 +225,9 @@ Seven things to know:
`conflicts` entry, as every block in the base grammar does. The generator offers an associativity
instead; taking it silently discards the parse in which the body continues.
- **End tags are not reserved**, a stray `{% endmap %}` parses as a `custom_tag` rather than an error — `reserved` takes no
`previous`, so the `tag_name` list cannot be added to a name at a time. Instead you may drop the `custom_tag` rule to avoid parsing end tags as custom tags.
`previous`, so the `tag_name` list cannot be added to a name at a time. Instead you may drop the `custom_tag` rule to avoid parsing end tags as custom tags. While the fallback
is there, stray words in one of your end tags (`{% endloop extra %}`) read as a `custom_tag` too, which
leaves your group with a missing-tag marker at the end of input instead of an `unexpected_argument`.
- **Your groups get missing-tag markers.** The scanner knows no group by name — a group is closed by `end`
followed by its opening tag's name — so the `alias($._missing_tag, $.missing_endloop_tag)` choice
above is all it takes: an unclosed `{% loop x %}`, or one left open inside an `{% if %}` that
+54 -17
View File
@@ -514,6 +514,9 @@ const django = grammar({
[$.timezone_block],
[$.with_block],
[$.binaryOperator],
[$.predicate],
[$._translate_option],
[$.unexpected_argument],
[$.library, $.load_tag],
[$._filtered_value_spaced],
[$._filter_expression_spaced],
@@ -561,15 +564,35 @@ const django = grammar({
template: ($) => repeat1(choice($.template_node, $.content)),
// the tags of a group; see startTag
simpleTagOpen: ($) => seq("{%", $._group_open_tag_read, optional(SEP)),
simpleTagClose: ($) => seq(optional(SEP), "%}"),
simpleTagClose: ($) =>
seq(optional($.unexpected_argument), optional(SEP), "%}"),
startTagOpen: ($) => seq("{%", $._group_open_tag_read, optional(SEP)),
startTagClose: ($) => seq($._group_open_tag_push, optional(SEP), "%}"),
startTagClose: ($) =>
seq(
optional($.unexpected_argument),
$._group_open_tag_push,
optional(SEP),
"%}",
),
followTagOpen: ($) => seq("{%", $._group_open_tag_read, optional(SEP)),
followTagClose: ($) => seq($._group_follow, optional(SEP), "%}"),
followTagClose: ($) =>
seq(
optional($.unexpected_argument),
$._group_follow,
optional(SEP),
"%}",
),
repeatTagOpen: ($) => seq("{%", $._group_open_tag_read, optional(SEP)),
repeatTagClose: ($) => seq($._group_repeat, optional(SEP), "%}"),
repeatTagClose: ($) =>
seq(
optional($.unexpected_argument),
$._group_repeat,
optional(SEP),
"%}",
),
endTagOpen: ($) => seq("{%", $._group_open_tag_read, optional(SEP)),
endTagClose: ($) => seq($._group_close, optional(SEP), "%}"),
endTagClose: ($) =>
seq(optional($.unexpected_argument), $._group_close, optional(SEP), "%}"),
content: ($) => /(?:[^\{]|\{[^\{#%}])+/,
// the separator between the parts of a tag; see SEP
_sep: ($) => /[ \t\r\n]+/,
@@ -1165,30 +1188,44 @@ const django = grammar({
* second and a third "else", the later ones are the strays. Reading the
* first as the stray instead parses just as well, so _group_held, which the
* scanner returns only for a name the innermost group already holds, puts
* the later reading at -1 against -2 for each tag flagged before its time.
* the later reading at -2 against -4 for each tag flagged before its time. Both
* cost more than an unexpected_argument, at -1, so a tag its group does take
* but with a word it does not is read as that tag rather than as a stray.
*/
unexpected_tag: ($) =>
choice(
prec.dynamic(
-1,
seq(
$.simpleTagOpen,
field("tag_name", choice(...NAMES_INSIDE_A_TAG_GROUP)),
repeat(seq(SEP, /[^\s%]+/)),
$._group_held,
$.simpleTagClose,
),
),
prec.dynamic(
-2,
seq(
$.simpleTagOpen,
field("tag_name", choice(...NAMES_INSIDE_A_TAG_GROUP)),
repeat(seq(SEP, /[^\s%]+/)),
optional($.unexpected_argument),
$._group_held,
optional(SEP),
"%}",
),
),
prec.dynamic(
-4,
seq(
$.simpleTagOpen,
field("tag_name", choice(...NAMES_INSIDE_A_TAG_GROUP)),
$.simpleTagClose,
),
),
),
/**
* Words a tag does not take, kept inside the tag they were written in. Every
* close utility accepts them before its "%}", so a misused tag keeps its own
* node, "{% else x %}" is still the else of its group, and error recovery
* has nothing to repair. Each word is a token of lexical precedence -1, so
* that a token an argument really takes wins wherever one is valid, even
* over a longer match: "b|upper" is still a filtered value. The node costs
* -1 of dynamic precedence, less than any unexpected_tag, and
* queries/errors.scm reports it.
*/
unexpected_argument: ($) =>
prec.dynamic(-1, repeat1(seq(SEP, token(prec(-1, /[^\s%]+/))))),
url_tag: ($) =>
tag(
"url",
+2
View File
@@ -41,3 +41,5 @@
(missing_plural_tag)] @error.missing_tag
(unexpected_tag) @error.unexpected_tag
(unexpected_argument) @error.unexpected_argument
+227 -139
View File
@@ -47,6 +47,18 @@
"simpleTagClose": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unexpected_argument"
},
{
"type": "BLANK"
}
]
},
{
"type": "CHOICE",
"members": [
@@ -93,6 +105,18 @@
"startTagClose": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unexpected_argument"
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_group_open_tag_push"
@@ -143,6 +167,18 @@
"followTagClose": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unexpected_argument"
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_group_follow"
@@ -193,6 +229,18 @@
"repeatTagClose": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unexpected_argument"
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_group_repeat"
@@ -243,6 +291,18 @@
"endTagClose": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unexpected_argument"
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_group_close"
@@ -7062,140 +7122,6 @@
"unexpected_tag": {
"type": "CHOICE",
"members": [
{
"type": "PREC_DYNAMIC",
"value": -1,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "simpleTagOpen"
},
{
"type": "FIELD",
"name": "tag_name",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "elif"
},
{
"type": "STRING",
"value": "else"
},
{
"type": "STRING",
"value": "empty"
},
{
"type": "STRING",
"value": "endautoescape"
},
{
"type": "STRING",
"value": "endblock"
},
{
"type": "STRING",
"value": "endblocktrans"
},
{
"type": "STRING",
"value": "endblocktranslate"
},
{
"type": "STRING",
"value": "endcache"
},
{
"type": "STRING",
"value": "endcomment"
},
{
"type": "STRING",
"value": "endfilter"
},
{
"type": "STRING",
"value": "endfor"
},
{
"type": "STRING",
"value": "endif"
},
{
"type": "STRING",
"value": "endifchanged"
},
{
"type": "STRING",
"value": "endlanguage"
},
{
"type": "STRING",
"value": "endlocalize"
},
{
"type": "STRING",
"value": "endlocaltime"
},
{
"type": "STRING",
"value": "endpartialdef"
},
{
"type": "STRING",
"value": "endspaceless"
},
{
"type": "STRING",
"value": "endtimezone"
},
{
"type": "STRING",
"value": "endverbatim"
},
{
"type": "STRING",
"value": "endwith"
},
{
"type": "STRING",
"value": "plural"
}
]
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_sep"
},
{
"type": "PATTERN",
"value": "[^\\s%]+"
}
]
}
},
{
"type": "SYMBOL",
"name": "_group_held"
},
{
"type": "SYMBOL",
"name": "simpleTagClose"
}
]
}
},
{
"type": "PREC_DYNAMIC",
"value": -2,
@@ -7304,17 +7230,143 @@
}
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unexpected_argument"
},
{
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "_group_held"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_sep"
},
{
"type": "PATTERN",
"value": "[^\\s%]+"
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "%}"
}
]
}
},
{
"type": "PREC_DYNAMIC",
"value": -4,
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "simpleTagOpen"
},
{
"type": "FIELD",
"name": "tag_name",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "elif"
},
{
"type": "STRING",
"value": "else"
},
{
"type": "STRING",
"value": "empty"
},
{
"type": "STRING",
"value": "endautoescape"
},
{
"type": "STRING",
"value": "endblock"
},
{
"type": "STRING",
"value": "endblocktrans"
},
{
"type": "STRING",
"value": "endblocktranslate"
},
{
"type": "STRING",
"value": "endcache"
},
{
"type": "STRING",
"value": "endcomment"
},
{
"type": "STRING",
"value": "endfilter"
},
{
"type": "STRING",
"value": "endfor"
},
{
"type": "STRING",
"value": "endif"
},
{
"type": "STRING",
"value": "endifchanged"
},
{
"type": "STRING",
"value": "endlanguage"
},
{
"type": "STRING",
"value": "endlocalize"
},
{
"type": "STRING",
"value": "endlocaltime"
},
{
"type": "STRING",
"value": "endpartialdef"
},
{
"type": "STRING",
"value": "endspaceless"
},
{
"type": "STRING",
"value": "endtimezone"
},
{
"type": "STRING",
"value": "endverbatim"
},
{
"type": "STRING",
"value": "endwith"
},
{
"type": "STRING",
"value": "plural"
}
]
}
@@ -7328,6 +7380,33 @@
}
]
},
"unexpected_argument": {
"type": "PREC_DYNAMIC",
"value": -1,
"content": {
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_sep"
},
{
"type": "TOKEN",
"content": {
"type": "PREC",
"value": -1,
"content": {
"type": "PATTERN",
"value": "[^\\s%]+"
}
}
}
]
}
}
},
"url_tag": {
"type": "SEQ",
"members": [
@@ -7821,6 +7900,15 @@
[
"binaryOperator"
],
[
"predicate"
],
[
"_translate_option"
],
[
"unexpected_argument"
],
[
"library",
"load_tag"
+499 -20
View File
File diff suppressed because it is too large. Load diff
+47244 -31157
View File
File diff suppressed because it is too large. Load diff
+129 -10
View File
@@ -380,13 +380,29 @@ Blocktrans With Plural And No Count
==================
Blocktrans Counting Two Bindings
:error
==================
{% blocktrans count n=x c=d %}one{% plural %}many{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(unexpected_argument))
(content)
(plural_block
(plural_tag)
(content)))
(endblocktrans_tag))
(content))
==================
Blocktrans With Nothing To Bind
@@ -400,13 +416,21 @@ Blocktrans With Nothing To Bind
==================
Blocktrans With An Unknown Option
:error
==================
{% blocktrans bogus %}hi{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(unexpected_argument))
(content))
(endblocktrans_tag))
(content))
==================
Blocktrans With Asvar And No Name
@@ -478,73 +502,155 @@ Blocktrans With Two Plurals
==================
Blocktrans With An Argument On Plural
:error
==================
{% blocktrans count n=x %}one{% plural extra %}many{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(identifier)
(filtered_value
(value
(variable_attribute
(identifier)))))
(content)
(plural_block
(plural_tag
(unexpected_argument))
(content)))
(endblocktrans_tag))
(content))
==================
Blocktrans With Trimmed Twice
:error
==================
{% blocktrans trimmed trimmed %}hi{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(unexpected_argument))
(content))
(endblocktrans_tag))
(content))
==================
Blocktrans With With Twice
:error
==================
{% blocktrans with a=b with c=d %}hi{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(unexpected_argument))
(content))
(endblocktrans_tag))
(content))
==================
Blocktrans With Context Twice
:error
==================
{% blocktrans context "a" context "b" %}hi{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(content))
(endblocktrans_tag))
(content))
==================
Blocktrans With Asvar Twice
:error
==================
{% blocktrans asvar x asvar y %}hi{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(identifier)
(unexpected_argument))
(content))
(endblocktrans_tag))
(content))
==================
Blocktrans With Count Twice
:error
==================
{% blocktrans count n=x count m=y %}a{% plural %}b{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(unexpected_argument))
(content)
(plural_block
(plural_tag)
(content)))
(endblocktrans_tag))
(content))
==================
Blocktranslate With Trimmed Twice
:error
==================
{% blocktranslate trimmed trimmed %}hi{% endblocktranslate %}
---
(template
(content)
(blocktranslate_group
(blocktranslate_block
(blocktranslate_tag
(unexpected_argument))
(content))
(endblocktranslate_tag))
(content))
==================
Blocktrans Repeating An Option Of The Tag Before It
@@ -570,10 +676,23 @@ Blocktrans Repeating An Option Of The Tag Before It
==================
Blocktrans With A Binding Twice
:error
==================
{% blocktrans with a=1 a=2 %}x{% endblocktrans %}
---
(template
(content)
(blocktranslate_group
(blocktrans_block
(blocktrans_tag
(identifier)
(filtered_value
(value
(literal
(number))))
(unexpected_argument))
(content))
(endblocktrans_tag))
(content))
+20 -1
View File
@@ -221,13 +221,31 @@ Cache Without A Fragment Name
==================
Cache With Anything After Using
:error
==================
{% cache 500 sidebar using="c" extra %}x{% endcache %}
---
(template
(content)
(cache_group
(cache_block
(cache_tag
(filtered_value
(value
(literal
(number))))
(identifier)
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(template
(content)))
(endcache_tag))
(content))
==================
Cache With An Empty Using
@@ -257,3 +275,4 @@ Cache With Using As Its Fragment Name
{% cache 500 using="c" %}x{% endcache %}
---
+11 -2
View File
@@ -48,14 +48,21 @@ Csp Nonce Attr With Media Keyword
==================
Csp Nonce Attr Takes One Argument
:error
==================
{% csp_nonce_attr "a" "b" %}
---
(ERROR)
(template
(content)
(csp_nonce_attr_tag
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(content))
==================
Csp Nonce Attr Rejects Unknown Keyword
@@ -68,6 +75,7 @@ Csp Nonce Attr Rejects Unknown Keyword
(ERROR)
==================
Csp Nonce Attr Rejects Repeated Keyword
:error
@@ -88,3 +96,4 @@ Csp Nonce Attr With Media Twice
{% csp_nonce_attr media="a" media="b" %}
---
+31 -2
View File
@@ -486,13 +486,27 @@ For Reversed With A Tag In Its Body
==================
For With Reversed Twice
:error
==================
{% for x in y reversed reversed %}a{% endfor %}
---
(template
(content)
(for_group
(for_block
(for_tag
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(unexpected_argument))
(template
(content)))
(endfor_tag))
(content))
==================
For With Reversed Before In
@@ -503,6 +517,7 @@ For With Reversed Before In
---
==================
For Over A Variable Named Reversed
==================
@@ -587,10 +602,24 @@ For With Reversed As Its Whole Sequence
==================
For With Reversed Three Times
:error
==================
{% for x in reversed reversed reversed %}a{% endfor %}
---
(template
(content)
(for_group
(for_block
(for_tag
(identifier)
(filtered_value
(value
(variable_attribute
(identifier))))
(unexpected_argument))
(template
(content)))
(endfor_tag))
(content))
+15 -1
View File
@@ -400,13 +400,26 @@ Language Without An Argument
==================
Language With Two Arguments
:error
==================
{% language "a" "b" %}x{% endlanguage %}
---
(template
(content)
(language_group
(language_block
(language_tag
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(template
(content)))
(endlanguage_tag))
(content))
==================
Language Name Filter
@@ -493,6 +506,7 @@ Language Name Filter With An Argument
---
==================
Translate With A Context Named After Noop
:error
+5 -2
View File
@@ -219,8 +219,11 @@ b
(ifchanged_block
(ifchanged_tag)
(template
(content)
(unexpected_tag)
(content)))
(else_block
(else_tag
(unexpected_argument))
(template
(content)))
(endifchanged_tag))
(content))
+10 -1
View File
@@ -233,9 +233,18 @@ Include With A Legacy Binding
==================
Include With A Second Name
:error
==================
{% include "t.html" "u.html" %}
---
(template
(content)
(include_tag
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(content))
+11 -2
View File
@@ -105,13 +105,22 @@ Localize With Another Argument
==================
Localize With Two Arguments
:error
==================
{% localize on off %}x{% endlocalize %}
---
(template
(content)
(localize_group
(localize_block
(localize_tag
(unexpected_argument))
(template
(content)))
(endlocalize_tag))
(content))
==================
Localize Unclosed
@@ -130,7 +139,6 @@ Localize Unclosed
(content)))
(missing_endlocalize_tag)))
==================
Localize Filter
==================
@@ -187,3 +195,4 @@ Unlocalize Filter With An Argument
{{ x|unlocalize:1 }}
---
+2 -1
View File
@@ -950,7 +950,8 @@ Endblock Naming No Open Block
(block_tag
(push_block))
(template
(unexpected_tag)
(unexpected_tag
(unexpected_argument))
(content)))
(missing_endblock_tag))))
(missing_endblock_tag)))
+19 -2
View File
@@ -81,23 +81,40 @@ Static Without A Path
==================
Static With A Second Path
:error
==================
{% static "a.css" "b.css" %}
---
(template
(content)
(static_tag
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(content))
==================
Static With Anything After As
:error
==================
{% static "a.css" as url junk %}
---
(template
(content)
(static_tag
(filtered_value
(value
(literal
(string))))
(identifier)
(unexpected_argument))
(content))
==================
Get Static Prefix
+31 -3
View File
@@ -64,13 +64,22 @@ Localtime With Another Argument
==================
Localtime With Two Arguments
:error
==================
{% localtime on off %}x{% endlocaltime %}
---
(template
(content)
(localtime_group
(localtime_block
(localtime_tag
(unexpected_argument))
(template
(content)))
(endlocaltime_tag))
(content))
==================
Timezone
@@ -152,13 +161,26 @@ Timezone Without An Argument
==================
Timezone With Two Arguments
:error
==================
{% timezone "a" "b" %}x{% endtimezone %}
---
(template
(content)
(timezone_group
(timezone_block
(timezone_tag
(filtered_value
(value
(literal
(string))))
(unexpected_argument))
(template
(content)))
(endtimezone_tag))
(content))
==================
Get Current Timezone
@@ -186,13 +208,18 @@ Get Current Timezone Without As
==================
Get Current Timezone With Anything After As
:error
==================
{% get_current_timezone as tz junk %}
---
(template
(content)
(get_current_timezone_tag
(identifier)
(unexpected_argument))
(content))
==================
Localtime Filter
@@ -272,3 +299,4 @@ Localtime Filter With An Argument
{{ x|localtime:1 }}
---
+35 -2
View File
@@ -68,23 +68,56 @@ With Multiple Variables
==================
With A Binding Twice
:error
==================
{% with a=1 a=2 %}x{% endwith %}
---
(template
(content)
(with_group
(with_block
(with_tag
(identifier)
(filtered_value
(value
(literal
(number))))
(unexpected_argument))
(template
(content)))
(endwith_tag))
(content))
==================
With A Binding Repeated Later
:error
==================
{% with a=1 b=2 a=3 %}x{% endwith %}
---
(template
(content)
(with_group
(with_block
(with_tag
(identifier)
(filtered_value
(value
(literal
(number))))
(identifier)
(filtered_value
(value
(literal
(number))))
(unexpected_argument))
(template
(content)))
(endwith_tag))
(content))
==================
With Repeating A Binding Of The Tag Before It