| 16 | const PROP_APPEND = MODE_PROP_APPEND; |
| 17 | |
| 18 | const evaluate = (h, built, fields, args) => { |
| 19 | let tmp; |
| 20 | |
| 21 | // `build()` used the first element of the operation list as |
| 22 | // temporary workspace. Now that `build()` is done we can use |
| 23 | // that space to track whether the current element is "dynamic" |
| 24 | // (i.e. it or any of its descendants depend on dynamic values). |
| 25 | built[0] = 0; |
| 26 | |
| 27 | for (let i = 1; i < built.length; i++) { |
| 28 | const type = built[i++]; |
| 29 | |
| 30 | // Set `built[0]`'s appropriate bits if this element depends on a dynamic value. |
| 31 | const value = built[i] ? ((built[0] |= type ? 1 : 2), fields[built[i++]]) : built[++i]; |
| 32 | |
| 33 | if (type === TAG_SET) { |
| 34 | args[0] = value; |
| 35 | } |
| 36 | else if (type === PROPS_ASSIGN) { |
| 37 | args[1] = Object.assign(args[1] || {}, value); |
| 38 | } |
| 39 | else if (type === PROP_SET) { |
| 40 | (args[1] = args[1] || {})[built[++i]] = value; |
| 41 | } |
| 42 | else if (type === PROP_APPEND) { |
| 43 | args[1][built[++i]] += (value + ''); |
| 44 | } |
| 45 | else if (type) { // type === CHILD_RECURSE |
| 46 | // Set the operation list (including the staticness bits) as |
| 47 | // `this` for the `h` call. |
| 48 | tmp = h.apply(value, evaluate(h, value, fields, ['', null])); |
| 49 | args.push(tmp); |
| 50 | |
| 51 | if (value[0]) { |
| 52 | // Set the 2nd lowest bit it the child element is dynamic. |
| 53 | built[0] |= 2; |
| 54 | } |
| 55 | else { |
| 56 | // Rewrite the operation list in-place if the child element is static. |
| 57 | // The currently evaluated piece `CHILD_RECURSE, 0, [...]` becomes |
| 58 | // `CHILD_APPEND, 0, tmp`. |
| 59 | // Essentially the operation list gets optimized for potential future |
| 60 | // re-evaluations. |
| 61 | built[i-2] = CHILD_APPEND; |
| 62 | built[i] = tmp; |
| 63 | } |
| 64 | } |
| 65 | else { // type === CHILD_APPEND |
| 66 | args.push(value); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | return args; |
| 71 | }; |
| 72 | |
| 73 | const build = function(statics) { |
| 74 | |