blob: 7c1222c935b3258ddd14b502a3554d90832b2462 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/shell/parser/combinators.h"
#include <algorithm>
#include <map>
namespace shell::parser {
fit::function<ParseResult(ParseResult)> Seq(fit::function<ParseResult(ParseResult)> a,
fit::function<ParseResult(ParseResult)> b) {
return [a = std::move(a), b = std::move(b)](ParseResult prefix) {
auto a_result = a(prefix);
if (a_result) {
return b(a_result);
}
return ParseResult::kEnd;
};
}
fit::function<ParseResult(ParseResult)> Seq(fit::function<ParseResult(ParseResult)> first) {
return first;
}
fit::function<ParseResult(ParseResult)> Alt(fit::function<ParseResult(ParseResult)> a) { return a; }
fit::function<ParseResult(ParseResult)> Alt(fit::function<ParseResult(ParseResult)> a,
fit::function<ParseResult(ParseResult)> b) {
return [a = std::move(a), b = std::move(b)](ParseResult prefix) {
auto a_result = a(prefix);
if (a_result && a_result.error_score() == 0) {
return a_result;
} else {
auto b_result = b(prefix);
if (a_result && (!b_result || b_result.error_score() >= a_result.error_score())) {
return a_result;
}
return b_result;
}
};
}
ParseResult Empty(ParseResult prefix) { return prefix; }
ParseResult EOS(ParseResult prefix) {
if (prefix.tail().empty()) {
return prefix;
}
return ParseResult::kEnd;
}
fit::function<ParseResult(ParseResult)> Not(fit::function<ParseResult(ParseResult)> inv) {
return [inv = std::move(inv)](ParseResult prefix) {
auto inv_result = inv(ParseResult(prefix.tail()));
if (inv_result && inv_result.error_score() == 0) {
return ParseResult::kEnd;
}
return prefix;
};
}
fit::function<ParseResult(ParseResult)> Multi(size_t min, size_t max,
fit::function<ParseResult(ParseResult)> child) {
if (min == 1 && max == 1) {
return child;
} else if (min > 0) {
if (max != std::numeric_limits<size_t>::max()) {
// TODO: If we can find a way to make the structure of Multi combinators constant-size, we
// could just treat the max limit like a regular limit and not a sentinel value, which would
// mean killing this conditional.
max -= 1;
}
// We have to parse at least one instance of the child, so parse it here, then recurse to parse
// the rest of the pattern.
return Seq(child.share(), Multi(min - 1, max, std::move(child)));
} else if (max == std::numeric_limits<size_t>::max()) {
// This is the same principle as the finite version in the last conditional, but we have to
// construct the next combinator in a closure otherwise this combinator recurses infinitely.
return Maybe([child = std::move(child)](ParseResult prefix) mutable {
auto child_result = child(prefix);
if (child_result && child_result.error_score() == prefix.error_score()) {
return Multi(0, std::numeric_limits<size_t>::max(), child.share())(std::move(child_result));
}
return child_result;
});
} else {
// Min = 0, max = <something finite>.
return Maybe(Multi(1, max, std::move(child)));
}
}
fit::function<ParseResult(ParseResult)> Multi(size_t count,
fit::function<ParseResult(ParseResult)> child) {
return Multi(count, count, std::move(child));
}
} // namespace shell::parser