diff options
author | Lucas Neves <lcneves@gmail.com> | 2017-09-17 23:56:00 -0400 |
---|---|---|
committer | Lucas Neves <lcneves@gmail.com> | 2017-09-25 22:01:56 -0400 |
commit | df4542814b4d217f31768d007b7fb513dc9c46ac (patch) | |
tree | 64cb6cc6e45b06ced59450382bd678dd5af45aff | |
parent | 45a06a36bc19baf6e93e6ff2c8b1fe72b208f225 (diff) | |
download | libcss-df4542814b4d217f31768d007b7fb513dc9c46ac.tar.gz |
Parse: rewrite flex shorthand parser to comply with standards
Parse: rewrite flex shorthand parser to conform to standards
-rw-r--r-- | src/parse/properties/flex.c | 357 | ||||
-rw-r--r-- | test/data/select/tests1.dat | 120 |
2 files changed, 250 insertions, 227 deletions
diff --git a/src/parse/properties/flex.c b/src/parse/properties/flex.c index f189b3b..dfec5bf 100644 --- a/src/parse/properties/flex.c +++ b/src/parse/properties/flex.c @@ -28,62 +28,21 @@ * If the input is invalid, then \a *ctx remains unchanged. */ -css_error flex_grow_helper(const css_token *token, css_fixed *number); -css_error flex_basis_helper(css_language *c, - const parserutils_vector *vector, int *ctx, - css_fixed *basis_length, uint32_t *basis_unit, - opcode_t *basis_op); - - -css_error flex_basis_helper(css_language *c, - const parserutils_vector *vector, int *ctx, - css_fixed *basis_length, uint32_t *basis_unit, - opcode_t *basis_op) -{ - css_error error; - error = css__parse_unit_specifier(c, vector, ctx, - UNIT_PX, basis_length, basis_unit); - - if (error == CSS_OK) { - if (*basis_unit & UNIT_ANGLE || - *basis_unit & UNIT_TIME || - *basis_unit & UNIT_FREQ) { - return CSS_INVALID; - } - *basis_op = FLEX_BASIS_SET; - } - - return error; -} - -css_error flex_grow_helper(const css_token *token, css_fixed *number) -{ - if (token->type != CSS_TOKEN_NUMBER) - return CSS_INVALID; - - size_t consumed = 0; - css_fixed num = css__number_from_lwc_string( - token->idata, false, &consumed); - - /* Invalid if there are trailing characters */ - if (consumed != lwc_string_length(token->idata)) - return CSS_INVALID; - - /* Invalid if number is negative */ - if (num < 0) - return CSS_INVALID; - - *number = num; - return CSS_OK; -} - css_error css__parse_flex(css_language *c, const parserutils_vector *vector, int *ctx, css_style *result) { int orig_ctx = *ctx; + int prev_ctx; const css_token *token; css_error error; + bool grow = true; + bool shrink = true; + bool basis = true; + css_style *grow_style; + css_style *shrink_style; + css_style *basis_style; + bool match; /* Firstly, handle inherit */ token = parserutils_vector_peek(vector, *ctx); @@ -92,16 +51,16 @@ css_error css__parse_flex(css_language *c, if (is_css_inherit(c, token)) { error = css_stylesheet_style_inherit(result, - CSS_PROP_FLEX_GROW); + CSS_PROP_FLEX_SHRINK); if (error != CSS_OK) return error; error = css_stylesheet_style_inherit(result, - CSS_PROP_FLEX_SHRINK); + CSS_PROP_FLEX_GROW); + if (error != CSS_OK) return error; - error = css_stylesheet_style_inherit(result, CSS_PROP_FLEX_BASIS); @@ -109,149 +68,9 @@ css_error css__parse_flex(css_language *c, parserutils_vector_iterate(vector, ctx); return error; - } - - /* Default values */ - opcode_t grow_op = FLEX_GROW_SET; - css_fixed grow_number = 0; - opcode_t shrink_op = FLEX_SHRINK_SET; - css_fixed shrink_number = INTTOFIX(1); - opcode_t basis_op = FLEX_BASIS_AUTO; - css_fixed basis_length = 0; - uint32_t basis_unit = UNIT_PX; - - /* Attempt to parse the various longhand properties */ - *ctx = orig_ctx; - size_t length = -1; - - do { - ++length; - token = parserutils_vector_iterate(vector, ctx); - } while (token != NULL); - - *ctx = orig_ctx; - - switch (length) { - case 1: - token = parserutils_vector_iterate(vector, ctx); - if (token == NULL || token->type != CSS_TOKEN_IDENT) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* - * Handle auto and none - * auto = flex: 1 1 auto; - * none = flex: 0 0 auto; - */ - bool match; - if ((lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match) || - (lwc_string_caseless_isequal( - token->idata, c->strings[NONE], - &match) == lwc_error_ok && match)) { - if ((lwc_string_caseless_isequal( - token->idata, c->strings[AUTO], - &match) == lwc_error_ok && match)) { - grow_number = INTTOFIX(1); - } - else { - shrink_number = 0; - } - - } - - /* Token must be either flex-basis or flex-grow */ - else { - *ctx = orig_ctx; - error = flex_basis_helper(c, vector, ctx, - &basis_length, &basis_unit, - &basis_op); - - if (error != CSS_OK) { - /* Positive number: equivalent of - * flex: <positive number> 1 0; */ - *ctx = orig_ctx; - token = parserutils_vector_iterate(vector, ctx); - error = flex_grow_helper( - token, &grow_number); - if (error != CSS_OK) { - *ctx = orig_ctx; - return CSS_INVALID; - } - basis_op = FLEX_BASIS_SET; - } - } - break; - - case 2: - /* First value must be flex-grow */ - token = parserutils_vector_iterate(vector, ctx); - error = flex_grow_helper( - token, &grow_number); - if (error != CSS_OK) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Second value must be either flex-basis or flex-shrink */ - int prev_ctx = *ctx; - error = flex_basis_helper(c, vector, ctx, - &basis_length, &basis_unit, &basis_op); - - if (error != CSS_OK) { - /* Two positive numbers: equivalent of - * flex: <number_1> <number_2> 0; */ - *ctx = prev_ctx; - token = parserutils_vector_iterate(vector, ctx); - error = flex_grow_helper( - token, &shrink_number); - if (error != CSS_OK) { - *ctx = orig_ctx; - return CSS_INVALID; - } - basis_op = FLEX_BASIS_SET; - } - break; - - case 3: - /* First value must be flex-grow */ - token = parserutils_vector_iterate(vector, ctx); - error = flex_grow_helper( - token, &grow_number); - if (error != CSS_OK) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Second value must be flex-shrink */ - token = parserutils_vector_iterate(vector, ctx); - error = flex_grow_helper( - token, &shrink_number); - if (error != CSS_OK) { - *ctx = orig_ctx; - return CSS_INVALID; - } - - /* Third value must be flex-basis */ - error = flex_basis_helper(c, vector, ctx, - &basis_length, &basis_unit, &basis_op); - if (error != CSS_OK) { - *ctx = orig_ctx; - return CSS_INVALID; - } - break; - - default: - return CSS_INVALID; } - + /* allocate styles */ - css_style *grow_style; - css_style *shrink_style; - css_style *basis_style; - error = css__stylesheet_style_create(c->sheet, &grow_style); if (error != CSS_OK) return error; @@ -260,59 +79,155 @@ css_error css__parse_flex(css_language *c, if (error != CSS_OK) { css__stylesheet_style_destroy(grow_style); return error; - } + } error = css__stylesheet_style_create(c->sheet, &basis_style); if (error != CSS_OK) { - css__stylesheet_style_destroy(shrink_style); css__stylesheet_style_destroy(grow_style); + css__stylesheet_style_destroy(shrink_style); return error; } - error = css__stylesheet_style_appendOPV(grow_style, - CSS_PROP_FLEX_GROW, 0, grow_op); - if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + /* Handle none, equivalent of flex: 0 0 auto; */ + if ((token->type == CSS_TOKEN_IDENT) && + (lwc_string_caseless_isequal( + token->idata, c->strings[NONE], + &match) == lwc_error_ok && match)) { + error = css__stylesheet_style_appendOPV(grow_style, + CSS_PROP_FLEX_GROW, 0, FLEX_GROW_SET); + if (error != CSS_OK) + goto css__parse_flex_cleanup; - error = css__stylesheet_style_append(grow_style, grow_number); - if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + error = css__stylesheet_style_append(grow_style, 0); + if (error != CSS_OK) + goto css__parse_flex_cleanup; - error = css__stylesheet_style_appendOPV(shrink_style, - CSS_PROP_FLEX_SHRINK, 0, shrink_op); - if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + error = css__stylesheet_style_appendOPV(shrink_style, + CSS_PROP_FLEX_SHRINK, 0, FLEX_SHRINK_SET); + if (error != CSS_OK) + goto css__parse_flex_cleanup; - error = css__stylesheet_style_append(shrink_style, shrink_number); - if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + error = css__stylesheet_style_append(shrink_style, 0); + if (error != CSS_OK) + goto css__parse_flex_cleanup; - error = css__stylesheet_style_appendOPV(basis_style, - CSS_PROP_FLEX_BASIS, 0, basis_op); - if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + error = css__stylesheet_style_appendOPV(basis_style, + CSS_PROP_FLEX_BASIS, 0, FLEX_BASIS_AUTO); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + grow = shrink = basis = false; + parserutils_vector_iterate(vector, ctx); + } + + /* Handle auto, equivalent of flex: 1 1 auto; */ + else if ((token->type == CSS_TOKEN_IDENT) && + (lwc_string_caseless_isequal( + token->idata, c->strings[AUTO], + &match) == lwc_error_ok && match)) { + error = css__stylesheet_style_appendOPV(grow_style, + CSS_PROP_FLEX_GROW, 0, FLEX_GROW_SET); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + error = css__stylesheet_style_append(grow_style, INTTOFIX(1)); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + error = css__stylesheet_style_appendOPV(shrink_style, + CSS_PROP_FLEX_SHRINK, 0, FLEX_SHRINK_SET); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + error = css__stylesheet_style_append(shrink_style, INTTOFIX(1)); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + error = css__stylesheet_style_appendOPV(basis_style, + CSS_PROP_FLEX_BASIS, 0, FLEX_BASIS_AUTO); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + grow = shrink = basis = false; + parserutils_vector_iterate(vector, ctx); + } + + /* Attempt to parse the various longhand properties */ + else do { + prev_ctx = *ctx; + error = CSS_OK; + + /* Ensure that we're not about to parse another inherit */ + token = parserutils_vector_peek(vector, *ctx); + if (token != NULL && is_css_inherit(c, token)) { + error = CSS_INVALID; + goto css__parse_flex_cleanup; + } - if (basis_op == (opcode_t) FLEX_BASIS_SET) { - error = css__stylesheet_style_append(basis_style, basis_length); + if ((grow) && + (error = css__parse_flex_grow(c, vector, + ctx, grow_style)) == CSS_OK) { + grow = false; + } else if ((basis) && + (error = css__parse_flex_basis(c, vector, + ctx, basis_style)) == CSS_OK) { + basis = false; + } else if ((shrink) && + (error = css__parse_flex_shrink(c, vector, + ctx, shrink_style)) == CSS_OK) { + shrink = false; + } + + if (error == CSS_OK) { + consumeWhitespace(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + } else { + /* Forcibly cause loop to exit */ + token = NULL; + } + } while (*ctx != prev_ctx && token != NULL); + + /* defaults */ + if (grow) { + error = css__stylesheet_style_appendOPV(grow_style, + CSS_PROP_FLEX_GROW, 0, FLEX_GROW_SET); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + error = css__stylesheet_style_append(grow_style, 0); if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + goto css__parse_flex_cleanup; + } + + if (shrink) { + error = css__stylesheet_style_appendOPV(shrink_style, + CSS_PROP_FLEX_SHRINK, 0, FLEX_SHRINK_SET); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + + error = css__stylesheet_style_append(shrink_style, INTTOFIX(1)); + if (error != CSS_OK) + goto css__parse_flex_cleanup; + } - error = css__stylesheet_style_append(basis_style, basis_unit); + if (basis) { + error = css__stylesheet_style_appendOPV(basis_style, + CSS_PROP_FLEX_BASIS, 0, FLEX_BASIS_AUTO); if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + goto css__parse_flex_cleanup; } error = css__stylesheet_merge_style(result, grow_style); if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + goto css__parse_flex_cleanup; error = css__stylesheet_merge_style(result, shrink_style); if (error != CSS_OK) - goto css__parse_flex_flow_cleanup; + goto css__parse_flex_cleanup; error = css__stylesheet_merge_style(result, basis_style); -css__parse_flex_flow_cleanup: +css__parse_flex_cleanup: css__stylesheet_style_destroy(basis_style); css__stylesheet_style_destroy(shrink_style); diff --git a/test/data/select/tests1.dat b/test/data/select/tests1.dat index 2d30083..a8b527d 100644 --- a/test/data/select/tests1.dat +++ b/test/data/select/tests1.dat @@ -6940,6 +6940,116 @@ word-spacing: normal writing-mode: horizontal-tb z-index: auto #reset +# +#tree +| div* +#ua +div { flex: 2 3 10px; } +#user +#errors +#expected: +align-content: stretch +align-items: stretch +align-self: auto +background-attachment: scroll +background-color: #00000000 +background-image: none +background-position: 0% 0% +background-repeat: repeat +border-collapse: separate +border-spacing: 0px 0px +border-top-color: #ff000000 +border-right-color: #ff000000 +border-bottom-color: #ff000000 +border-left-color: #ff000000 +border-top-style: none +border-right-style: none +border-bottom-style: none +border-left-style: none +border-top-width: 2px +border-right-width: 2px +border-bottom-width: 2px +border-left-width: 2px +bottom: auto +box-sizing: content-box +break-after: auto +break-before: auto +break-inside: auto +caption-side: top +clear: none +clip: auto +color: #ff000000 +column-count: auto +column-fill: balance +column-gap: normal +column-rule-color: #ff000000 +column-rule-style: none +column-rule-width: 2px +column-span: none +column-width: auto +content: normal +counter-increment: none +counter-reset: none +cursor: auto +direction: ltr +display: inline +empty-cells: show +flex-basis: 10px +flex-direction: row +flex-grow: 2.000 +flex-shrink: 3.000 +flex-wrap: nowrap +float: none +font-family: sans-serif +font-size: 12pt +font-style: normal +font-variant: normal +font-weight: normal +height: auto +justify-content: flex-start +left: auto +letter-spacing: normal +line-height: normal +list-style-image: none +list-style-position: outside +list-style-type: disc +margin-top: 0px +margin-right: 0px +margin-bottom: 0px +margin-left: 0px +max-height: none +max-width: none +min-height: 0px +min-width: 0px +opacity: 1.000 +order: 0 +outline-color: invert +outline-style: none +outline-width: 2px +overflow-x: visible +overflow-y: visible +padding-top: 0px +padding-right: 0px +padding-bottom: 0px +padding-left: 0px +position: static +quotes: none +right: auto +table-layout: auto +text-align: default +text-decoration: none +text-indent: 0px +text-transform: none +top: auto +unicode-bidi: normal +vertical-align: baseline +visibility: visible +white-space: normal +width: auto +word-spacing: normal +writing-mode: horizontal-tb +z-index: auto +#reset #tree | div* @@ -7214,7 +7324,7 @@ cursor: auto direction: ltr display: inline empty-cells: show -flex-basis: 0px +flex-basis: auto flex-direction: row flex-grow: 0.000 flex-shrink: 1.000 @@ -7495,9 +7605,7 @@ z-index: auto #tree | div* #ua -div { } -#user -div { } +div { flex: 2 3em; } #errors #expected: align-content: stretch @@ -7546,9 +7654,9 @@ cursor: auto direction: ltr display: inline empty-cells: show -flex-basis: auto +flex-basis: 3em flex-direction: row -flex-grow: 0.000 +flex-grow: 2.000 flex-shrink: 1.000 flex-wrap: nowrap float: none |