enforce key uniqueness on with expression, fix scanner.c
This commit is contained in:
1 parent
6105fd9002
commit
356cc3a885
10 files changed
+53165
-53162
No files matched your search
+38
-39
@@ -2137,6 +2137,10 @@
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_kwarg_name"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "variable",
|
||||
@@ -4690,6 +4694,10 @@
|
||||
"value": "include"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_tag_open"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
@@ -7849,37 +7857,12 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "REPEAT1",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "PATTERN",
|
||||
"value": "[ \\t\\r\\n]+"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "variable",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "="
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "filtered_value"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"type": "SYMBOL",
|
||||
"name": "_tag_open"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_tag_kwargs"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
@@ -7961,12 +7944,25 @@
|
||||
},
|
||||
"extras": [],
|
||||
"conflicts": [
|
||||
["template"],
|
||||
["predicate"],
|
||||
["library", "load"],
|
||||
["_translate_option"],
|
||||
["_filtered_value_spaced"],
|
||||
["_filter_expression_spaced"]
|
||||
[
|
||||
"template"
|
||||
],
|
||||
[
|
||||
"predicate"
|
||||
],
|
||||
[
|
||||
"library",
|
||||
"load"
|
||||
],
|
||||
[
|
||||
"_translate_option"
|
||||
],
|
||||
[
|
||||
"_filtered_value_spaced"
|
||||
],
|
||||
[
|
||||
"_filter_expression_spaced"
|
||||
]
|
||||
],
|
||||
"precedences": [],
|
||||
"externals": [
|
||||
@@ -8020,7 +8016,10 @@
|
||||
}
|
||||
],
|
||||
"inline": [],
|
||||
"supertypes": ["template_tag", "template_block_groups"],
|
||||
"supertypes": [
|
||||
"template_tag",
|
||||
"template_block_groups"
|
||||
],
|
||||
"reserved": {
|
||||
"global": [
|
||||
{
|
||||
@@ -8143,4 +8142,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3000,4 +3000,4 @@
|
||||
"type": "}}",
|
||||
"named": false
|
||||
}
|
||||
]
|
||||
]
|
||||
+53012
-53073
File diff suppressed because it is too large.
Load diff
+17
-11
@@ -65,13 +65,14 @@ typedef Array(OpenTag) Stack;
|
||||
|
||||
struct Scanner {
|
||||
bool has_error;
|
||||
/* one bit per option of the blocktranslate tag being read, by the order of
|
||||
* translate_options. Kept out of the union below, whose members share their
|
||||
* storage with each other. */
|
||||
/* the "name=value" argument names the tag being read has been given, each
|
||||
* followed by NAME_SEP. parse_bits refuses a repeated keyword argument, and
|
||||
* the set of names is open, so this remembers the names rather than a mask
|
||||
* of known ones. Kept out of the union, as translate_seen is. */
|
||||
/* Everything below is readable only while has_error is false: the error
|
||||
* string shares its storage with all of it.
|
||||
*
|
||||
* translate_seen holds one bit per option of the blocktranslate tag being
|
||||
* read, by the order of translate_options. seen_kwargs holds the
|
||||
* "name=value" argument names the tag has been given, each followed by
|
||||
* NAME_SEP: parse_bits refuses a repeated keyword argument and the set of
|
||||
* names is open, so the names are kept rather than a mask of known ones. */
|
||||
union {
|
||||
struct {
|
||||
uint8_t translate_seen;
|
||||
@@ -92,8 +93,11 @@ static enum TokenType pop_token_for_kind(TagKind kind) {
|
||||
|
||||
static void reset_scanner(struct Scanner *const scanner) {
|
||||
if (scanner->has_error) {
|
||||
// sets everything to 0 values: 0, '\0', false, null
|
||||
memset(&scanner, 0, sizeof(scanner));
|
||||
/* The error shares its storage with the state below, so none of that is
|
||||
* readable here and none of it holds a pointer to free: scanner_error
|
||||
* resets before it sets has_error, which is what frees them. Zeroing the
|
||||
* whole struct clears the error and the state it overlays at once. */
|
||||
memset(scanner, 0, sizeof(*scanner));
|
||||
} else {
|
||||
scanner->translate_seen = 0;
|
||||
array_delete(&scanner->seen_kwargs);
|
||||
@@ -167,9 +171,11 @@ write_serialization_error:;
|
||||
char *iter = buffer;
|
||||
|
||||
iter += write_code(scanner->has_error + '0', iter);
|
||||
/* Both of these overlay the error string, so they are only read when there is
|
||||
* none; an error state serializes as the empty option mask and no names. */
|
||||
// five options fit in five bits, which stays inside printable ASCII
|
||||
iter += write_code(scanner->translate_seen + '0', iter);
|
||||
for (unsigned i = 0; i < scanner->seen_kwargs.size; ++i) {
|
||||
iter += write_code((scanner->has_error ? 0 : scanner->translate_seen) + '0', iter);
|
||||
for (unsigned i = 0; !scanner->has_error && i < scanner->seen_kwargs.size; ++i) {
|
||||
int32_t code = *array_get(&scanner->seen_kwargs, i);
|
||||
unsigned write_amt = write_code(code, iter);
|
||||
if (write_amt == 0) {
|
||||
|
||||
Reference in new issue
Block a user