Admit private syntax text before named producers grow

This commit is contained in:
2026-09-24 18:52:39 -07:00
parent 8d52dab97c
commit 6b0ef99eca
12 changed files with 761 additions and 33 deletions
+92 -18
View File
@@ -1018,6 +1018,16 @@ fn edit_positions_from_tokens(
token: impl Fn(usize) -> Lexeme,
count: usize,
value_ends: Option<&BTreeMap<usize, usize>>,
) -> Result<Vec<(Id, EditDeclaration)>, Box<Diagnostic>> {
edit_positions_from_tokens_with_text(source, unit, token, count, value_ends, |_, _| Ok(()))
}
fn edit_positions_from_tokens_with_text(
source: &str,
unit: &SourceUnit,
token: impl Fn(usize) -> Lexeme,
count: usize,
value_ends: Option<&BTreeMap<usize, usize>>,
text: impl FnMut(usize, Span) -> Result<(), Box<Diagnostic>>,
) -> Result<Vec<(Id, EditDeclaration)>, Box<Diagnostic>> {
let mut ends: Vec<_> = (0..count).map(|at| token(at).span.end).collect();
let mut stack = Vec::new();
@@ -1029,12 +1039,15 @@ fn edit_positions_from_tokens(
_ => {}
}
}
struct Positions<'a, F> {
struct Positions<'a, F, H> {
token_at: F,
ends: Vec<usize>,
value_ends: Option<&'a BTreeMap<usize, usize>>,
text: H,
}
impl<F: Fn(usize) -> Lexeme> Positions<'_, F> {
impl<F: Fn(usize) -> Lexeme, H: FnMut(usize, Span) -> Result<(), Box<Diagnostic>>>
Positions<'_, F, H>
{
fn token(&self, start: usize) -> usize {
let mut low = 0;
let mut high = self.ends.len();
@@ -1048,24 +1061,28 @@ fn edit_positions_from_tokens(
}
low
}
fn fields(&self, fields: &BTreeMap<String, Ast>) -> BTreeMap<String, EditField> {
fn fields(
&mut self,
fields: &BTreeMap<String, Ast>,
) -> Result<BTreeMap<String, EditField>, Box<Diagnostic>> {
fields
.iter()
.map(|(key, ast)| {
let value = self.value(ast);
let value = self.value(ast)?;
let start = (self.token_at)(self.token(value.span.start) - 1).span.start;
let end = (self.token_at)(self.token(value.span.end)).span.end;
(
(self.text)(key.len(), Span { start, end })?;
Ok((
key.clone(),
EditField {
span: Span { start, end },
value,
},
)
))
})
.collect()
}
fn value(&self, ast: &Ast) -> EditValue {
fn value(&mut self, ast: &Ast) -> Result<EditValue, Box<Diagnostic>> {
let index = self.token(ast.offset());
let span = Span {
start: ast.offset(),
@@ -1080,21 +1097,28 @@ fn edit_positions_from_tokens(
}),
};
let kind = match ast {
Ast::Object(fields, _) => EditKind::Record(self.fields(fields)),
Ast::Array(items, _) => {
EditKind::List(items.iter().map(|item| self.value(item)).collect())
Ast::Object(fields, _) => EditKind::Record(self.fields(fields)?),
Ast::Array(items, _) => EditKind::List(
items
.iter()
.map(|item| self.value(item))
.collect::<Result<_, _>>()?,
),
Ast::Reference(alias, _) => {
(self.text)(alias.len(), span)?;
EditKind::Reference(alias.clone())
}
Ast::Reference(alias, _) => EditKind::Reference(alias.clone()),
Ast::HistoricalUuid(id, _) => EditKind::HistoricalUuid(*id),
_ => EditKind::Atom,
};
EditValue { span, kind }
Ok(EditValue { span, kind })
}
}
let positions = Positions {
let mut positions = Positions {
token_at: &token,
ends,
value_ends,
text,
};
unit.declarations
.iter()
@@ -1132,7 +1156,7 @@ fn edit_positions_from_tokens(
start: declaration.body.start - 1,
end: declaration.body.end + 1,
},
kind: EditKind::Record(positions.fields(&declaration.fields)),
kind: EditKind::Record(positions.fields(&declaration.fields)?),
},
},
))
@@ -1196,11 +1220,24 @@ impl Parser<'_> {
if self.current().class != TokenClass::String {
return Err(self.error("Expected a double-quoted string."));
}
#[cfg(test)]
if self.mixed.is_some() {
let span = self.current().span;
let raw = &self.source[span.start..span.end];
let value = self
.mixed
.as_mut()
.expect("mixed quoted consumer")
.quoted_text(raw, span)?;
self.cursor += 1;
return Ok(value);
}
let value = serde_json::from_str(self.text()).unwrap();
self.cursor += 1;
Ok(value)
}
fn identifier(&mut self) -> Result<String, Error> {
self.own_text(self.text().len(), self.current().span)?;
let value = self.text().to_owned();
if !crate::valid_alias(&value) {
return Err(self.error(std::format!("Invalid or reserved alias '{value}'.")));
@@ -1230,11 +1267,32 @@ impl Parser<'_> {
message: "Expected UUID in 8-4-4-4-12 hexadecimal form.".into(),
});
}
Id::parse_str(&value).map_err(|_| Error {
let id = Id::parse_str(&value).map_err(|_| Error {
code: "invalid_source",
offset,
message: "Invalid UUID identity.".into(),
})
})?;
let bytes = value.len();
drop(value);
self.release_text(bytes);
Ok(id)
}
fn own_text(&mut self, bytes: usize, span: Span) -> Result<(), Error> {
#[cfg(test)]
if let Some(mixed) = &mut self.mixed {
mixed.own_text(bytes, span)?;
}
#[cfg(not(test))]
let _ = (bytes, span);
Ok(())
}
fn release_text(&mut self, bytes: usize) {
#[cfg(test)]
if let Some(mixed) = &mut self.mixed {
mixed.release_text(bytes);
}
#[cfg(not(test))]
let _ = bytes;
}
fn fields(&mut self) -> Result<BTreeMap<String, Ast>, Error> {
self.take("{")?;
@@ -1242,6 +1300,13 @@ impl Parser<'_> {
while self.text() != "}" {
let offset = self.current().span.start;
let (key, value, _) = self.field()?;
self.own_text(
key.len(),
Span {
start: offset,
end: offset,
},
)?;
if fields.insert(key.clone(), value).is_some() {
return Err(Error {
code: "invalid_source",
@@ -1249,12 +1314,16 @@ impl Parser<'_> {
message: std::format!("Duplicate field '{key}'."),
});
}
let bytes = key.len();
drop(key);
self.release_text(bytes);
}
self.take("}")?;
Ok(fields)
}
fn field(&mut self) -> Result<(String, Ast, Span), Error> {
self.syntax_entry()?;
self.own_text(self.text().len(), self.current().span)?;
let key = self.text().to_owned();
if !matches!(
self.current().class,
@@ -1328,6 +1397,9 @@ impl Parser<'_> {
offset,
message: "Expected a UUID after uuid.".into(),
})?;
let bytes = value.len();
drop(value);
self.release_text(bytes);
Ok(Ast::HistoricalUuid(id, offset))
}
"@" => {
@@ -1368,6 +1440,7 @@ impl Parser<'_> {
Ok(Ast::Literal(value, offset))
}
TokenClass::Identifier | TokenClass::Keyword => {
self.own_text(self.text().len(), self.current().span)?;
let value = self.text().to_owned();
self.cursor += 1;
Ok(Ast::Word(value, offset))
@@ -1514,6 +1587,7 @@ impl Parser<'_> {
}
} else {
let (key, value, span) = self.field()?;
self.own_text(key.len(), span)?;
let declaration = &mut declarations[owner];
if declaration.fields.insert(key.clone(), value).is_some() {
return Err(Error {
@@ -1584,8 +1658,8 @@ impl Parser<'_> {
return Err(self.error("Use the short source8 analysis declaration word."));
}
self.syntax_entry()?;
let word = self.text().to_owned();
let kind = declaration_kind(&word)
let word = self.current().text(self.source);
let kind = declaration_kind(word)
.ok_or_else(|| self.error(format!("Unknown declaration '{word}'.")))?;
#[cfg(test)]
if let Some(mixed) = &mut self.mixed {