blob: 7c1408ae7ac261f1ff2053dc1e56aa0a74a8c131 [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) {
return [child = std::move(child), min, max](ParseResult prefix) {
size_t score_floor = prefix.error_score();
size_t count = 0;
ParseResult result = prefix;
for (ParseResult next = ParseResult::kEnd; result && count < max; ++count) {
next = child(result);
if ((!next || next.error_score() > score_floor) && count >= min) {
return result;
}
// If result becomes a null parse result at this point, it means two things:
// 1) We've had a hard parse failure. That means parsing failed *and error recovery failed*.
// 2) We didn't reach the minimum number of repetitions before that hard failure.
//
// The next thing that will happen is the loop will end and we will propagate that hard
// failure by returning the null parse result.
result = next;
}
return result;
};
}
fit::function<ParseResult(ParseResult)> Multi(size_t count,
fit::function<ParseResult(ParseResult)> child) {
return Multi(count, count, std::move(child));
}
} // namespace shell::parser