repl: Always use parser, allow trailing ; in assignments
We now properly shell out to the parser instead of hacking stuff together with a regex. Stuff we get for free by doing this: - Optional trailing semicolon - Declaring nested attribute sets - String identifiers, and future proofing for eventual grammar improvements to identifiers - Dynamic attributes Change-Id: Ibf1ad815e5e27caf162df05ea5ba5b1b4955d9c9
This commit is contained in:
@@ -46,6 +46,7 @@ error_message_for(grammar::v1::seps) = "expecting separators";
|
||||
error_message_for(grammar::v1::path::forbid_prefix_triple_slash) = "too many slashes in path";
|
||||
error_message_for(grammar::v1::path::forbid_prefix_double_slash_no_interp) = "path has a trailing slash";
|
||||
error_message_for(grammar::v1::expr) = "expecting expression";
|
||||
error_message_for(grammar::v1::repl_root::expr_or_binding) = "expecting expression or a binding";
|
||||
error_message_for(grammar::v1::expr::unary) = "expecting expression";
|
||||
error_message_for(grammar::v1::binding::equal) = "expecting '='";
|
||||
error_message_for(grammar::v1::expr::lambda::arg) = "expecting identifier";
|
||||
@@ -430,7 +431,7 @@ template<> struct BuildAST<grammar::v1::inherit> : change_head<InheritState> {
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct BuildAST<grammar::v1::_binding::value> {
|
||||
template<> struct BuildAST<grammar::v1::binding::value> {
|
||||
static void apply0(BindingState & s, State & ps) {
|
||||
s.value = s->popExprOnly();
|
||||
}
|
||||
@@ -442,6 +443,52 @@ template<> struct BuildAST<grammar::v1::binding> : change_head<BindingState> {
|
||||
}
|
||||
};
|
||||
|
||||
struct BindingsStateRepl : ExprState {
|
||||
std::map<Symbol, std::unique_ptr<Expr>> symbols;
|
||||
};
|
||||
|
||||
template<> struct BuildAST<grammar::v1::repl_binding> : change_head<BindingState> {
|
||||
static void success(const auto & in, BindingState & b, BindingsStateRepl & s, State & ps) {
|
||||
auto path = std::move(b.attrs);
|
||||
AttrName name = std::move(path.front());
|
||||
path.erase(path.begin());
|
||||
if (name.expr)
|
||||
throw ParseError({
|
||||
.msg = HintFmt("dynamic attributes not allowed in REPL"),
|
||||
.pos = ps.positions[ps.at(in)]
|
||||
});
|
||||
Symbol symbol = name.symbol;
|
||||
|
||||
if (auto iter = s.symbols.find(symbol); iter != s.symbols.end())
|
||||
ps.dupAttr({symbol}, iter->second->getPos(), ps.at(in));
|
||||
|
||||
if (path.empty()) {
|
||||
// key = value
|
||||
s.symbols.emplace(symbol, std::move(b.value));
|
||||
} else {
|
||||
// key.stuff = value
|
||||
auto attrs = std::make_unique<ExprSet>(b.value->getPos());
|
||||
ps.addAttr(&*attrs, std::move(path), std::move(b.value), ps.at(in));
|
||||
s.symbols.emplace(symbol, std::move(attrs));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using ReplRootState = std::variant<std::unique_ptr<Expr>, ExprReplBindings>;
|
||||
|
||||
template<> struct BuildAST<grammar::v1::repl_bindings> : change_head<BindingsStateRepl> {
|
||||
static void success0(BindingsStateRepl & b, ReplRootState & r, State &) {
|
||||
r = ExprReplBindings { std::move(b.symbols) };
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct BuildAST<grammar::v1::repl_root::expression> : change_head<ExprState> {
|
||||
static void success0(ExprState & inner, ReplRootState & outer, State & ps) {
|
||||
auto [_pos, expr] = inner.finish(ps);
|
||||
outer = std::move(expr);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct BuildAST<grammar::v1::expr::id> {
|
||||
static void apply(const auto & in, ExprState & s, State & ps) {
|
||||
if (in.string_view() == "__curPos")
|
||||
|
||||
Reference in New Issue
Block a user