Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Finished initial implementation of format expression parsing.
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisLoer committed Aug 15, 2018
1 parent 31c17fc commit ccba131
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 102 deletions.
2 changes: 2 additions & 0 deletions cmake/core-files.cmake
Expand Up @@ -460,6 +460,7 @@ set(MBGL_CORE_FILES
include/mbgl/style/expression/expression.hpp
include/mbgl/style/expression/find_zoom_curve.hpp
include/mbgl/style/expression/format_expression.hpp
include/mbgl/style/expression/formatted.hpp
include/mbgl/style/expression/get_covering_stops.hpp
include/mbgl/style/expression/interpolate.hpp
include/mbgl/style/expression/interpolator.hpp
Expand Down Expand Up @@ -488,6 +489,7 @@ set(MBGL_CORE_FILES
src/mbgl/style/expression/expression.cpp
src/mbgl/style/expression/find_zoom_curve.cpp
src/mbgl/style/expression/format_expression.cpp
src/mbgl/style/expression/formatted.cpp
src/mbgl/style/expression/get_covering_stops.cpp
src/mbgl/style/expression/interpolate.cpp
src/mbgl/style/expression/is_constant.cpp
Expand Down
1 change: 1 addition & 0 deletions include/mbgl/style/expression/expression.hpp
Expand Up @@ -134,6 +134,7 @@ enum class Kind : int32_t {
Any,
All,
Comparison,
FormatExpression,
};

class Expression {
Expand Down
16 changes: 13 additions & 3 deletions include/mbgl/style/expression/format_expression.hpp
@@ -1,6 +1,7 @@
#pragma once

#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>

Expand All @@ -9,12 +10,20 @@
namespace mbgl {
namespace style {
namespace expression {

struct FormatExpressionSection {
FormatExpressionSection(std::unique_ptr<Expression> text_,
optional<std::unique_ptr<Expression>> fontScale_,
optional<std::unique_ptr<Expression>> textFont_);

std::shared_ptr<Expression> text;
optional<std::shared_ptr<Expression>> fontScale;
optional<std::shared_ptr<Expression>> textFont;
};

class FormatExpression : public Expression {
public:
FormatExpression(std::unique_ptr<Expression> text,
optional<std::unique_ptr<Expression>> fontScale,
optional<std::unique_ptr<Expression>> textFont);
FormatExpression(std::vector<FormatExpressionSection> sections);

EvaluationResult evaluate(const EvaluationContext&) const override;
static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
Expand All @@ -32,6 +41,7 @@ class FormatExpression : public Expression {
mbgl::Value serialize() const override;
std::string getOperator() const override { return "format"; }
private:
std::vector<FormatExpressionSection> sections;
std::unique_ptr<Expression> text;
optional<std::unique_ptr<Expression>> fontScale;
optional<std::unique_ptr<Expression>> textFont;
Expand Down
38 changes: 38 additions & 0 deletions include/mbgl/style/expression/formatted.hpp
@@ -0,0 +1,38 @@
#pragma once

#include <mbgl/util/optional.hpp>

#include <vector>
#include <string>

namespace mbgl {
namespace style {
namespace expression {

struct FormattedSection {
FormattedSection(std::string text_, optional<double> fontScale_, optional<std::string> fontStack_)
: text(std::move(text_))
, fontScale(std::move(fontScale_))
, fontStack(std::move(fontStack_))
{}
std::string text;
optional<double> fontScale;
optional<std::string> fontStack;
};

class Formatted {
public:
Formatted(std::vector<FormattedSection> sections_)
: sections(std::move(sections_))
{}

bool operator==(const Formatted& ) const {
return false; // TODO
}
private:
std::vector<FormattedSection> sections;
};

} // namespace expression
} // namespace style
} // namespace mbgl
2 changes: 2 additions & 0 deletions include/mbgl/style/expression/value.hpp
@@ -1,6 +1,7 @@
#pragma once

#include <mbgl/style/expression/collator.hpp>
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/position.hpp>
#include <mbgl/style/types.hpp>
Expand All @@ -25,6 +26,7 @@ using ValueBase = variant<
std::string,
Color,
Collator,
Formatted,
mapbox::util::recursive_wrapper<std::vector<Value>>,
mapbox::util::recursive_wrapper<std::unordered_map<std::string, Value>>>;
struct Value : ValueBase {
Expand Down
4 changes: 4 additions & 0 deletions src/mbgl/style/conversion/function.cpp
Expand Up @@ -211,6 +211,10 @@ static optional<std::unique_ptr<Expression>> convertLiteral(type::Type type, con
[&] (const type::CollatorType&) -> optional<std::unique_ptr<Expression>> {
assert(false); // No properties use this type.
return nullopt;
},
[&] (const type::FormattedType&) -> optional<std::unique_ptr<Expression>> {
assert(false); // No properties use this type.
return nullopt;
}
);
}
Expand Down
200 changes: 101 additions & 99 deletions src/mbgl/style/expression/format_expression.cpp
@@ -1,4 +1,3 @@
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/expression/format_expression.hpp>
#include <mbgl/style/expression/literal.hpp>
#include <mbgl/util/string.hpp>
Expand All @@ -7,13 +6,22 @@ namespace mbgl {
namespace style {
namespace expression {

FormatExpression::FormatExpression(std::unique_ptr<Expression> text_,
optional<std::unique_ptr<Expression>> fontScale_,
optional<std::unique_ptr<Expression>> textFont_)
: Expression(Kind::FormatExpression, type::Formatted)
, text(std::move(text_))
, fontScale(std::move(fontScale_))
, textFont(std::move(textFont_))
FormatExpressionSection::FormatExpressionSection(std::unique_ptr<Expression> text_,
optional<std::unique_ptr<Expression>> fontScale_,
optional<std::unique_ptr<Expression>> textFont_)
: text(std::move(text_))
{
if (fontScale_) {
fontScale = std::shared_ptr<Expression>(std::move(*fontScale_));
}
if (textFont_) {
textFont = std::shared_ptr<Expression>(std::move(*textFont_));
}
}

FormatExpression::FormatExpression(std::vector<FormatExpressionSection> sections_)
: Expression(Kind::FormatExpression, type::Formatted)
, sections(std::move(sections_))
{}

using namespace mbgl::style::conversion;
Expand All @@ -32,128 +40,122 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct

std::vector<FormatExpressionSection> sections;
for (std::size_t i = 1; i < argsLength - 1; i += 2) {
auto options = arrayMember(value, 1);
auto textArg = arrayMember(value, i);
ParseResult text = ctx.parse(textArg, 1, {type::Value});
if (!text) {
return ParseResult();
}
auto options = arrayMember(value, i + 1);
if (!isObject(options)) {
ctx.error("Collator options argument must be an object.");
ctx.error("Format options argument must be an object.");
return ParseResult();
}

ParseResult text = ctx.parse(args[i], 1, ValueType);
if (!text) return null;
const kind = text.type.kind;
if (kind !== 'string' && kind !== 'value' && kind !== 'null')
return context.error(`Formatted text type must be 'string', 'value', or 'null'.`);

const options = (args[i + 1]: any);
if (typeof options !== "object" || Array.isArray(options))
return context.error(`Format options argument must be an object.`);

let scale = null;
if (options['font-scale']) {
scale = context.parse(options['font-scale'], 1, NumberType);
if (!scale) return null;
const optional<Convertible> fontScaleOption = objectMember(options, "font-scale");
ParseResult fontScale;
if (fontScaleOption) {
fontScale = ctx.parse(*fontScaleOption, 1, {type::Number});
if (!fontScale) {
return ParseResult();
}
}

let font = null;
if (options['text-font']) {
font = context.parse(options['text-font'], 1, array(StringType));
if (!font) return null;
}
sections.push({text, scale, font});
}

return new FormatExpression(sections);

auto options = arrayMember(value, 1);
if (!isObject(options)) {
ctx.error("Collator options argument must be an object.");
return ParseResult();
}

const optional<Convertible> caseSensitiveOption = objectMember(options, "case-sensitive");
ParseResult caseSensitive;
if (caseSensitiveOption) {
caseSensitive = ctx.parse(*caseSensitiveOption, 1, {type::Boolean});
} else {
caseSensitive = { std::make_unique<Literal>(false) };
}
if (!caseSensitive) {
return ParseResult();
}

const optional<Convertible> diacriticSensitiveOption = objectMember(options, "diacritic-sensitive");
ParseResult diacriticSensitive;
if (diacriticSensitiveOption) {
diacriticSensitive = ctx.parse(*diacriticSensitiveOption, 1, {type::Boolean});
} else {
diacriticSensitive = { std::make_unique<Literal>(false) };
}
if (!diacriticSensitive) {
return ParseResult();
}

const optional<Convertible> localeOption = objectMember(options, "locale");
ParseResult locale;
if (localeOption) {
locale = ctx.parse(*localeOption, 1, {type::String});
if (!locale) {
return ParseResult();
const optional<Convertible> textFontOption = objectMember(options, "text-font");
ParseResult textFont;
if (textFontOption) {
textFont = ctx.parse(*textFontOption, 1, {type::Array(type::String)});
if (!textFont) {
return ParseResult();
}
}
sections.emplace_back(std::move(*text), std::move(fontScale), std::move(textFont));
}

return ParseResult(std::make_unique<FormatExpression>(std::move(*caseSensitive), std::move(*diacriticSensitive), std::move(locale)));
return ParseResult(std::make_unique<FormatExpression>(std::move(sections)));
}

void FormatExpression::eachChild(const std::function<void(const Expression&)>& fn) const {
fn(*caseSensitive);
fn(*diacriticSensitive);
if (locale) {
fn(**locale);
for (auto& section : sections) {
fn(*section.text);
if (section.fontScale) {
fn(**section.fontScale);
}
if (section.textFont) {
fn(**section.textFont);
}
}
}

bool FormatExpression::operator==(const Expression& e) const {
if (e.getKind() == Kind::FormatExpression) {
auto rhs = static_cast<const FormatExpression*>(&e);
if ((locale && (!rhs->locale || **locale != **(rhs->locale))) ||
(!locale && rhs->locale)) {
if (sections.size() != rhs->sections.size()) {
return false;
}
return *caseSensitive == *(rhs->caseSensitive) &&
*diacriticSensitive == *(rhs->diacriticSensitive);
for (std::size_t i = 0; i < sections.size(); i++) {
const auto& lhsSection = sections.at(i);
const auto& rhsSection = rhs->sections.at(i);
if (*lhsSection.text != *rhsSection.text) {
return false;
}
if ((lhsSection.fontScale && (!rhsSection.fontScale || **lhsSection.fontScale != **rhsSection.fontScale)) ||
(!lhsSection.fontScale && rhsSection.fontScale)) {
return false;
}
if ((lhsSection.textFont && (!rhsSection.textFont || **lhsSection.textFont != **rhsSection.textFont)) ||
(!lhsSection.textFont && rhsSection.textFont)) {
return false;
}
}
return true;
}
return false;
}

mbgl::Value FormatExpression::serialize() const {
std::unordered_map<std::string, mbgl::Value> options;
options["case-sensitive"] = caseSensitive->serialize();
options["diacritic-sensitive"] = diacriticSensitive->serialize();
if (locale) {
options["locale"] = (*locale)->serialize();
std::vector<mbgl::Value> serialized{{ std::string("format") }};
for (const auto& section : sections) {
serialized.push_back(section.text->serialize());
std::unordered_map<std::string, mbgl::Value> options;
if (section.fontScale) {
options["font-scale"] = (*section.fontScale)->serialize();
}
if (section.textFont) {
options["text-font"] = (*section.textFont)->serialize();
}
serialized.push_back(options);
}
return std::vector<mbgl::Value>{{ std::string("collator"), options }};
return serialized;
}

EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) const {
auto caseSensitiveResult = caseSensitive->evaluate(params);
if (!caseSensitiveResult) {
return caseSensitiveResult.error();
}
auto diacriticSensitiveResult = diacriticSensitive->evaluate(params);
if (!diacriticSensitiveResult) {
return diacriticSensitiveResult.error();
}

if (locale) {
auto localeResult = (*locale)->evaluate(params);
if (!localeResult) {
return localeResult.error();
std::vector<FormattedSection> evaluatedSections;
for (const auto& section : sections) {
auto textResult = section.text->evaluate(params);
if (!textResult) {
return textResult.error();
}

optional<double> evaluatedFontScale;
if (section.fontScale) {
auto fontScaleResult = (*section.fontScale)->evaluate(params);
if (!fontScaleResult) {
return fontScaleResult.error();
}
evaluatedFontScale = fontScaleResult->get<double>();
}

optional<std::string> evaluatedTextFont;
if (section.textFont) {
auto textFontResult = (*section.textFont)->evaluate(params);
if (!textFontResult) {
return textFontResult.error();
}
evaluatedTextFont = textFontResult->get<std::string>();
}
return Collator(caseSensitiveResult->get<bool>(), diacriticSensitiveResult->get<bool>(), localeResult->get<std::string>());
} else {
return Collator(caseSensitiveResult->get<bool>(), diacriticSensitiveResult->get<bool>());
evaluatedSections.emplace_back(textResult->get<std::string>(), evaluatedFontScale, evaluatedTextFont);
}
return Formatted(evaluatedSections);
}

} // namespace expression
Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/style/expression/formatted.cpp
@@ -0,0 +1,2 @@
#include <mbgl/style/expression/formatted.hpp>

0 comments on commit ccba131

Please sign in to comment.