69 lines
2.3 KiB
Rust
69 lines
2.3 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2023 Alain Zscheile <fogti+devel@ytrizja.de>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
use std::sync::Arc;
|
|
|
|
use crate::{
|
|
lex::{Token, TokenKind as Tok},
|
|
none_up, Env as ParseEnv, Error as Perr, ErrorCtx as PeCtx, ErrorKind as Pek, EvEqSourceSpan,
|
|
MaybeParse, Parse, Result as Pres,
|
|
};
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct Record<V>(pub Vec<(EvEqSourceSpan, Option<Arc<str>>, V)>);
|
|
|
|
impl<V: Parse> MaybeParse for Record<V> {
|
|
const DFL_CTX: PeCtx = PeCtx::Record;
|
|
|
|
fn maybe_parse(env: &mut ParseEnv<'_>) -> Pres<Option<Self>> {
|
|
none_up!(env.lxr.got(Tok::LBrace));
|
|
let mut fields: Vec<(_, Option<Arc<str>>, _)> = Vec::new();
|
|
|
|
// warning: this code executes in O(|fields|²)
|
|
loop {
|
|
let span_start;
|
|
let name = {
|
|
let mut lxrnxt = env.lxr.clone();
|
|
let Token { kind, span } = match lxrnxt.next_in_noeof(PeCtx::Record) {
|
|
Err(e) => {
|
|
env.lxr = lxrnxt;
|
|
return Err(e);
|
|
}
|
|
Ok(x) => x,
|
|
};
|
|
span_start = span.offset();
|
|
|
|
match kind {
|
|
Tok::DotIdent(i) => {
|
|
if env.lxr.expect(Tok::Assign, PeCtx::Record).is_ok() {
|
|
if fields.iter().any(|(_, j, _)| j.as_ref() == Some(&i)) {
|
|
return Err(Perr {
|
|
span,
|
|
kind: Pek::RecordDupIdent(i),
|
|
});
|
|
}
|
|
// "fronttrack"
|
|
env.lxr = lxrnxt;
|
|
Some(i)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
Tok::RBrace => break,
|
|
_ => None,
|
|
}
|
|
};
|
|
let expr = V::parse(env)?;
|
|
let span_end = env.lxr.offset();
|
|
env.lxr.expect(Tok::SemiColon, PeCtx::Record)?;
|
|
fields.push(((span_start..span_end).into(), name, expr));
|
|
}
|
|
|
|
env.lxr.expect(Tok::RBrace, PeCtx::Record)?;
|
|
Ok(Some(Record(fields)))
|
|
}
|
|
}
|