From 177d9baa45a1b8d325bb42202d7ac72133dd8dc0 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 3 Oct 2020 20:19:47 +0100 Subject: parse: calc() test and fixup. --- src/bytecode/bytecode.h | 14 ++++++ src/parse/properties/css_property_parser_gen.c | 2 +- src/parse/properties/utils.c | 66 ++++++++++++++++++-------- test/data/parse2/INDEX | 1 + test/data/parse2/calc.dat | 7 +++ test/dump.h | 45 ++++++++++++++++++ 6 files changed, 115 insertions(+), 20 deletions(-) create mode 100644 test/data/parse2/calc.dat diff --git a/src/bytecode/bytecode.h b/src/bytecode/bytecode.h index 92040b4..7c21d50 100644 --- a/src/bytecode/bytecode.h +++ b/src/bytecode/bytecode.h @@ -34,6 +34,14 @@ enum flag { FLAG_UNSET = (FLAG_VALUE_UNSET << 1), }; +enum calc_opcodes { + CALC_PUSH_VALUE = 'V', + CALC_ADD = '+', + CALC_SUBTRACT = '-', + CALC_MULTIPLY = '*', + CALC_DIVIDE = '/', + CALC_FINISH = '=', +}; typedef enum unit { UNIT_LENGTH = (1u << 8), @@ -128,6 +136,12 @@ static inline bool isInherit(css_code_t OPV) return getFlagValue(OPV) == FLAG_VALUE_INHERIT; } +static inline bool isCalc(css_code_t OPV) +{ + /* Note, this relies on all _CALC values being the same ultimately */ + return getValue(OPV) == 0x7f; +} + #endif diff --git a/src/parse/properties/css_property_parser_gen.c b/src/parse/properties/css_property_parser_gen.c index 1260f28..622ce16 100644 --- a/src/parse/properties/css_property_parser_gen.c +++ b/src/parse/properties/css_property_parser_gen.c @@ -330,7 +330,7 @@ void output_calc(FILE *outputf, struct keyval *parseid, struct keyval_list *kvli kind = ckv->key; fprintf(outputf, - "if ((token->type == CSS_TOKEN_IDENT) && " + "if ((token->type == CSS_TOKEN_FUNCTION) && " "(lwc_string_caseless_isequal(token->idata, c->strings[CALC], &match) == lwc_error_ok && match))" " {\n" "\t\terror = css__parse_calc(c, vector, ctx, result, buildOPV(%s, 0, %s), %s);\n" diff --git a/src/parse/properties/utils.c b/src/parse/properties/utils.c index cce9717..7f9d9d2 100644 --- a/src/parse/properties/utils.c +++ b/src/parse/properties/utils.c @@ -1373,8 +1373,10 @@ css__parse_calc_value(css_language *c, int orig_ctx = *ctx; const css_token *token; - token = parserutils_vector_iterate(vector, ctx); + /* On entry, we are already pointing at the value to parse, so peek it */ + token = parserutils_vector_peek(vector, *ctx); if (tokenIsChar(token, '(')) { + parserutils_vector_iterate(vector, ctx); error = css__parse_calc_sum(c, vector, ctx, result); if (error != CSS_OK) { return error; @@ -1384,7 +1386,8 @@ css__parse_calc_value(css_language *c, if (!tokenIsChar(token, ')')) { return CSS_INVALID; } - + /* Consume the close-paren to complete this value */ + parserutils_vector_iterate(vector, ctx); } else switch (token->type) { case CSS_TOKEN_NUMBER: /* Fall through */ case CSS_TOKEN_DIMENSION: /* Fall through */ @@ -1400,7 +1403,7 @@ css__parse_calc_value(css_language *c, return error; } - error = css__stylesheet_style_vappend(result, 3, (css_code_t) 'V', length, unit); + error = css__stylesheet_style_vappend(result, 3, (css_code_t) CALC_PUSH_VALUE, length, unit); } break; @@ -1409,6 +1412,11 @@ css__parse_calc_value(css_language *c, break; } + token = parserutils_vector_peek(vector, *ctx); + while (token->type == CSS_TOKEN_S) { + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + } return error; } @@ -1439,7 +1447,10 @@ css__parse_calc_product(css_language *c, if (token == NULL) { error = CSS_INVALID; break; - } else if (tokenIsChar(token, ')')) + } else if ( + tokenIsChar(token, ')') || + tokenIsChar(token, '+') || + tokenIsChar(token, '-')) break; else if (tokenIsChar(token, '*')) multiplication = true; @@ -1450,15 +1461,21 @@ css__parse_calc_product(css_language *c, break; } /* Consume that * or / now */ - token = parserutils_vector_iterate(vector, ctx); + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + while (token->type == CSS_TOKEN_S) { + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + } /* parse another value */ error = css__parse_calc_value(c, vector, ctx, result); if (error != CSS_OK) break; /* emit the multiplication/division operator */ - error = css__stylesheet_style_append(result, (css_code_t) (multiplication ? '*' : '/')); + error = css__stylesheet_style_append(result, + (css_code_t) (multiplication ? CALC_MULTIPLY : CALC_DIVIDE)); } while (1); /* We've fallen off, either we had an error or we're left with ')' */ return error; @@ -1498,7 +1515,13 @@ css__parse_calc_sum(css_language *c, break; } /* Consume that + or - now */ - token = parserutils_vector_iterate(vector, ctx); + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + + while (token->type == CSS_TOKEN_S) { + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + } /* parse another product */ error = css__parse_calc_product(c, vector, ctx, result); @@ -1506,7 +1529,7 @@ css__parse_calc_sum(css_language *c, break; /* emit the addition/subtraction operator */ - error = css__stylesheet_style_append(result, (css_code_t) (addition ? '+' : '-')); + error = css__stylesheet_style_append(result, (css_code_t) (addition ? CALC_ADD : CALC_SUBTRACT)); } while (1); /* We've fallen off, either we had an error or we're left with ')' */ return error; @@ -1524,16 +1547,15 @@ css_error css__parse_calc(css_language *c, css_error error = CSS_OK; css_style *calc_style = NULL; - token = parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); if (token == NULL) { *ctx = orig_ctx; return CSS_INVALID; } - if (!tokenIsChar(token, '(')) { - /* If we don't get an open-paren, give up now */ - *ctx = orig_ctx; - return CSS_INVALID; + while (token->type == CSS_TOKEN_S) { + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); } error = css__stylesheet_style_create(c->sheet, &calc_style); @@ -1545,27 +1567,33 @@ css_error css__parse_calc(css_language *c, goto cleanup; error = css__stylesheet_style_append(calc_style, (css_code_t) unit); + if (error != CSS_OK) + goto cleanup; error = css__parse_calc_sum(c, vector, ctx, calc_style); if (error != CSS_OK) goto cleanup; - token = parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + while (token->type == CSS_TOKEN_S) { + parserutils_vector_iterate(vector, ctx); + token = parserutils_vector_peek(vector, *ctx); + } if (!tokenIsChar(token, ')')) { /* If we don't get a close-paren, give up now */ error = CSS_INVALID; goto cleanup; } + /* Swallow that close paren */ + parserutils_vector_iterate(vector, ctx); + /* Append the indicator that the calc is finished */ - error = css__stylesheet_style_append(calc_style, (css_code_t) '='); + error = css__stylesheet_style_append(calc_style, (css_code_t) CALC_FINISH); if (error != CSS_OK) goto cleanup; - /* TODO: Once we're OK to do so, merge the style */ - (void)result; - /* error = css__stylesheet_style_merge_style(result, calc_style); */ - + error = css__stylesheet_merge_style(result, calc_style); cleanup: css__stylesheet_style_destroy(calc_style); if (error != CSS_OK) { diff --git a/test/data/parse2/INDEX b/test/data/parse2/INDEX index e4a369c..7bc4295 100644 --- a/test/data/parse2/INDEX +++ b/test/data/parse2/INDEX @@ -24,3 +24,4 @@ multicol.dat Multi-column layout property tests flexbox.dat Flexbox properties and shorthands tests units.dat Length unit tests dodgy-media-block.dat Media block with incomplete ruleset +calc.dat calc() tests diff --git a/test/data/parse2/calc.dat b/test/data/parse2/calc.dat new file mode 100644 index 0000000..95abf6c --- /dev/null +++ b/test/data/parse2/calc.dat @@ -0,0 +1,7 @@ +#data +* { height: calc(50vh + 10px)} +#errors +#expected +| * +| height: /* -> 0px */ calc(50vh 10px + =) +#reset \ No newline at end of file diff --git a/test/dump.h b/test/dump.h index f585788..054194a 100644 --- a/test/dump.h +++ b/test/dump.h @@ -640,6 +640,12 @@ static void dump_unit(css_fixed val, uint32_t unit, char **ptr) case UNIT_KHZ: *ptr += sprintf(*ptr, "kHz"); break; + case UNIT_CALC_ANY: + *ptr += sprintf(*ptr, "any"); + break; + case UNIT_CALC_NUMBER: + *ptr += sprintf(*ptr, "number"); + break; } } @@ -796,6 +802,45 @@ void dump_bytecode(css_style *style, char **ptr, uint32_t depth) *ptr += sprintf(*ptr, "revert"); } else if (getFlagValue(opv) == FLAG_VALUE_UNSET) { *ptr += sprintf(*ptr, "unset"); + } else if (isCalc(opv)) { + /* First entry is a unit */ + uint32_t unit = *((uint32_t *)bytecode); + ADVANCE(sizeof(unit)); + *ptr += sprintf(*ptr, "/* -> "); + dump_unit(0, unit, ptr); + *ptr += sprintf(*ptr, " */ calc("); + css_code_t calc_opcode; + while ((calc_opcode = *((css_code_t *)bytecode)) != CALC_FINISH) { + ADVANCE(sizeof(calc_opcode)); + switch (calc_opcode) { + case CALC_ADD: + *ptr += sprintf(*ptr, "+ "); + break; + case CALC_SUBTRACT: + *ptr += sprintf(*ptr, "- "); + break; + case CALC_MULTIPLY: + *ptr += sprintf(*ptr, "* "); + break; + case CALC_DIVIDE: + *ptr += sprintf(*ptr, "/ "); + break; + case CALC_PUSH_VALUE: { + css_fixed num = *((css_fixed *)bytecode); + ADVANCE(sizeof(num)); + uint32_t unit = *((uint32_t *)bytecode); + ADVANCE(sizeof(unit)); + dump_unit(num, unit, ptr); + *ptr += sprintf(*ptr, " "); + break; + } + default: + *ptr += sprintf(*ptr, "??%d ", calc_opcode); + break; + } + } + ADVANCE(sizeof(calc_opcode)); + *ptr += sprintf(*ptr, "=)"); } else { value = getValue(opv); -- cgit v1.2.3