private Function<Contexts.FeaturePostMatch, Object> attributeValueProducer(AttributeDefinition attribute) {
    Object type = attribute.type();

    // some expression features are hoisted to the top-level for attribute values for brevity,
    // so just map them to what the equivalent expression syntax would be and parse as an expression.
    Map<String, Object> value = new HashMap<>();
    if ("match_key".equals(type)) {
      value.put("value", "${match_key}");
    } else if ("match_value".equals(type)) {
      value.put("value", "${match_value}");
    } else {
      if (type != null) {
        value.put("type", type);
      }
      if (attribute.coalesce() != null) {
        value.put("coalesce", attribute.coalesce());
      } else if (attribute.value() != null) {
        value.put("value", attribute.value());
      } else if (attribute.tagValue() != null) {
        value.put("tag_value", attribute.tagValue());
      } else if (attribute.argValue() != null) {
        value.put("arg_value", attribute.argValue());
      } else {
        value.put("tag_value", attribute.key());
      }
    }

    return ConfigExpressionParser.parse(value, tagValueProducer, featurePostMatchContext, Object.class);
  }
Produces logic that generates attribute values based on configuration and input data. If both a constantValue
configuration and a tagValue configuration are set, this is likely a mistake, and the constantValue will take
precedence.

@param attribute - attribute definition configured from YML
@return a function that generates an attribute value from a {@link SourceFeature} based on an attribute
        configuration.
planetiler-custommap/src/main/java/com/onthegomap/planetiler/custommap/ConfiguredFeature.java