1use std::collections::{BTreeMap, HashMap};
5use std::ops::Range;
6use std::sync::OnceLock;
7
8use crate::lex::{lex, BinaryValue, LexError, Token, TokenKind};
9
10#[derive(Debug, Clone, PartialEq)]
12pub enum Value {
13 Reference(u64),
15 Integer(i64),
17 Real(f64),
19 Enumeration(String),
21 String(Vec<u8>),
23 Binary(BinaryValue),
25 Resource(String),
27 Omitted,
29 Derived,
31 List(Vec<Value>),
33 Typed(String, Box<Value>),
35}
36
37#[derive(Debug, Clone, PartialEq)]
39pub struct PartialRecord {
40 pub name: String,
42 pub parameters: Vec<Value>,
44}
45
46#[derive(Debug, Clone, PartialEq)]
48pub struct RawRecord {
49 pub id: u64,
51 pub partials: Vec<PartialRecord>,
53 pub span: Range<usize>,
55}
56
57#[derive(Debug, Clone, PartialEq)]
59pub struct HeaderRecord {
60 pub name: String,
62 pub parameters: Vec<Value>,
64}
65
66#[derive(Debug, Clone, PartialEq)]
68pub struct DataSection {
69 pub parameters: Vec<Value>,
71 pub records: Vec<u64>,
73}
74
75#[derive(Debug, Clone, PartialEq)]
77pub struct AnchorEntry {
78 pub name: String,
80 pub value: Value,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
86pub struct ReferenceEntry {
87 pub name: String,
89 pub uri: String,
91}
92
93#[derive(Debug, Clone, PartialEq)]
95pub struct Exchange {
96 pub header: Vec<HeaderRecord>,
98 pub anchors: Vec<AnchorEntry>,
100 pub references: Vec<ReferenceEntry>,
102 pub data: Vec<DataSection>,
104 pub signature: Option<Range<usize>>,
106 pub records: BTreeMap<u64, RawRecord>,
108 entity_ids: EntityIndex,
109}
110
111#[derive(Debug, Default)]
112struct EntityIndex(OnceLock<HashMap<String, Vec<u64>>>);
113
114impl Clone for EntityIndex {
115 fn clone(&self) -> Self {
116 Self::default()
117 }
118}
119
120impl PartialEq for EntityIndex {
121 fn eq(&self, _other: &Self) -> bool {
122 true
123 }
124}
125
126impl Exchange {
127 fn entity_ids(&self) -> &HashMap<String, Vec<u64>> {
128 self.entity_ids.0.get_or_init(|| {
129 let mut entity_ids = HashMap::<String, Vec<u64>>::new();
130 for (&id, record) in &self.records {
131 for partial in &record.partials {
132 if let Some(ids) = entity_ids.get_mut(partial.name.as_str()) {
133 ids.push(id);
134 } else {
135 entity_ids.insert(partial.name.clone(), vec![id]);
136 }
137 }
138 }
139 entity_ids
140 })
141 }
142
143 pub(crate) fn entities(&self, name: &str) -> impl Iterator<Item = (u64, &RawRecord)> {
144 self.entity_ids()
145 .get(name)
146 .into_iter()
147 .flatten()
148 .filter_map(|id| self.records.get(id).map(|record| (*id, record)))
149 }
150
151 pub(crate) fn entities_any<'a>(
152 &'a self,
153 names: &[&str],
154 ) -> impl Iterator<Item = (u64, &'a RawRecord)> {
155 let mut ids = names
156 .iter()
157 .filter_map(|name| self.entity_ids().get(*name))
158 .flatten()
159 .copied()
160 .collect::<Vec<_>>();
161 ids.sort_unstable();
162 ids.dedup();
163 ids.into_iter()
164 .filter_map(|id| self.records.get(&id).map(|record| (id, record)))
165 }
166}
167
168#[derive(Debug, thiserror::Error)]
170pub enum ParseError {
171 #[error(transparent)]
173 Lex(#[from] LexError),
174 #[error("{message} at byte {offset}")]
176 Syntax {
177 offset: usize,
179 message: String,
181 },
182}
183
184pub fn parse(input: &[u8]) -> Result<Exchange, ParseError> {
186 Parser {
187 tokens: lex(input)?,
188 at: 0,
189 depth: 0,
190 }
191 .exchange()
192}
193
194struct Parser {
195 tokens: Vec<Token>,
196 at: usize,
197 depth: usize,
198}
199
200impl Parser {
201 fn exchange(mut self) -> Result<Exchange, ParseError> {
202 self.name("ISO-10303-21")?;
203 self.punct(&TokenKind::Semicolon)?;
204 self.name("HEADER")?;
205 self.punct(&TokenKind::Semicolon)?;
206 let mut header = Vec::new();
207 while !self.peek_name("ENDSEC") {
208 let name = self.take_name()?;
209 let parameters = self.parameters()?;
210 self.punct(&TokenKind::Semicolon)?;
211 header.push(HeaderRecord { name, parameters });
212 }
213 self.name("ENDSEC")?;
214 self.punct(&TokenKind::Semicolon)?;
215 let mut anchors = Vec::new();
216 if self.peek_name("ANCHOR") {
217 self.at += 1;
218 self.punct(&TokenKind::Semicolon)?;
219 while !self.peek_name("ENDSEC") {
220 let TokenKind::Resource(name) = self.next_kind()? else {
221 return self.err("expected anchor name");
222 };
223 self.punct(&TokenKind::Equals)?;
224 let value = self.value()?;
225 self.punct(&TokenKind::Semicolon)?;
226 anchors.push(AnchorEntry { name, value });
227 }
228 self.at += 1;
229 self.punct(&TokenKind::Semicolon)?;
230 }
231 let mut reference_entries = Vec::new();
232 if self.peek_name("REFERENCE") {
233 self.at += 1;
234 self.punct(&TokenKind::Semicolon)?;
235 while !self.peek_name("ENDSEC") {
236 let TokenKind::Resource(name) = self.next_kind()? else {
237 return self.err("expected reference name");
238 };
239 self.punct(&TokenKind::Equals)?;
240 let TokenKind::Resource(uri) = self.next_kind()? else {
241 return self.err("expected reference URI");
242 };
243 self.punct(&TokenKind::Semicolon)?;
244 reference_entries.push(ReferenceEntry { name, uri });
245 }
246 self.at += 1;
247 self.punct(&TokenKind::Semicolon)?;
248 }
249 let mut data = Vec::new();
250 let mut records = BTreeMap::new();
251 while self.peek_name("DATA") {
252 self.at += 1;
253 let parameters = if self.peek(&TokenKind::LParen) {
254 self.parameters()?
255 } else {
256 Vec::new()
257 };
258 self.punct(&TokenKind::Semicolon)?;
259 let mut ids = Vec::new();
260 while !self.peek_name("ENDSEC") {
261 let record = self.record()?;
262 let id = record.id;
263 if records.insert(id, record).is_some() {
264 return self.err("duplicate instance name");
265 }
266 ids.push(id);
267 }
268 self.name("ENDSEC")?;
269 self.punct(&TokenKind::Semicolon)?;
270 data.push(DataSection {
271 parameters,
272 records: ids,
273 });
274 }
275 let signature = if self.peek_name("SIGNATURE") {
276 let start = self.current_offset();
277 self.at += 1;
278 self.punct(&TokenKind::Semicolon)?;
279 while !self.peek_name("ENDSEC") {
280 self.at += 1;
281 if self.at >= self.tokens.len() {
282 return self.err("unterminated SIGNATURE section");
283 }
284 }
285 self.at += 1;
286 self.punct(&TokenKind::Semicolon)?;
287 Some(start..self.previous_end())
288 } else {
289 None
290 };
291 self.name("END-ISO-10303-21")?;
292 self.punct(&TokenKind::Semicolon)?;
293 if self.at != self.tokens.len() {
294 return self.err("tokens after exchange terminator");
295 }
296 let anchor_bindings = anchors
297 .iter()
298 .map(|anchor| (anchor.name.clone(), anchor.value.clone()))
299 .collect::<BTreeMap<_, _>>();
300 if anchor_bindings.len() != anchors.len() {
301 return self.err("duplicate anchor name");
302 }
303 let mut resolver = AnchorResolver::new(&anchor_bindings);
304 for anchor in &mut anchors {
305 anchor.value = resolver
306 .resolve_root(&anchor.value)
307 .map_err(|message| ParseError::Syntax { offset: 0, message })?;
308 }
309 for record in records.values_mut() {
310 for partial in &mut record.partials {
311 for value in &mut partial.parameters {
312 *value =
313 resolver
314 .resolve_root(value)
315 .map_err(|message| ParseError::Syntax {
316 offset: record.span.start,
317 message,
318 })?;
319 }
320 }
321 }
322 for anchor in &anchors {
323 let mut refs = Vec::new();
324 references(&anchor.value, &mut refs);
325 if refs.into_iter().any(|id| !records.contains_key(&id)) {
326 return self.err("unresolved instance reference in anchor binding");
327 }
328 }
329 for record in records.values() {
330 let mut refs = Vec::new();
331 for partial in &record.partials {
332 for value in &partial.parameters {
333 references(value, &mut refs);
334 }
335 }
336 if refs.into_iter().any(|id| !records.contains_key(&id)) {
337 return Self::err_at(record.span.start, "unresolved instance reference");
338 }
339 }
340 Ok(Exchange {
341 header,
342 anchors,
343 references: reference_entries,
344 data,
345 signature,
346 records,
347 entity_ids: EntityIndex::default(),
348 })
349 }
350
351 fn record(&mut self) -> Result<RawRecord, ParseError> {
352 let start = self.current_offset();
353 let TokenKind::Instance(id) = self.next_kind()? else {
354 return self.err("expected instance name");
355 };
356 self.punct(&TokenKind::Equals)?;
357 let partials = if self.peek(&TokenKind::LParen) {
358 self.at += 1;
359 let mut parts = Vec::new();
360 while !self.peek(&TokenKind::RParen) {
361 parts.push(self.partial()?);
362 }
363 self.at += 1;
364 if !parts.windows(2).all(|w| w[0].name < w[1].name) {
365 return Self::err_at(start, "complex partial records are not alphabetical");
366 }
367 parts
368 } else {
369 vec![self.partial()?]
370 };
371 self.punct(&TokenKind::Semicolon)?;
372 Ok(RawRecord {
373 id,
374 partials,
375 span: start..self.previous_end(),
376 })
377 }
378
379 fn partial(&mut self) -> Result<PartialRecord, ParseError> {
380 let name = self.take_name()?;
381 let parameters = self.parameters()?;
382 Ok(PartialRecord { name, parameters })
383 }
384
385 fn parameters(&mut self) -> Result<Vec<Value>, ParseError> {
386 const MAX_VALUE_DEPTH: usize = 256;
387 if self.depth >= MAX_VALUE_DEPTH {
388 return self.err("parameter nesting exceeds 256 levels");
389 }
390 self.depth += 1;
391 let result = self.parameters_inner();
392 self.depth -= 1;
393 result
394 }
395
396 fn parameters_inner(&mut self) -> Result<Vec<Value>, ParseError> {
397 self.punct(&TokenKind::LParen)?;
398 let mut values = Vec::new();
399 if self.peek(&TokenKind::RParen) {
400 self.at += 1;
401 return Ok(values);
402 }
403 loop {
404 values.push(self.value()?);
405 if self.peek(&TokenKind::Comma) {
406 self.at += 1;
407 } else {
408 break;
409 }
410 }
411 self.punct(&TokenKind::RParen)?;
412 Ok(values)
413 }
414
415 fn value(&mut self) -> Result<Value, ParseError> {
416 match self.next_kind()? {
417 TokenKind::Instance(v) => Ok(Value::Reference(v)),
418 TokenKind::Integer(v) => Ok(Value::Integer(v)),
419 TokenKind::Real(v) => Ok(Value::Real(v)),
420 TokenKind::Enumeration(v) => Ok(Value::Enumeration(v)),
421 TokenKind::String(v) => Ok(Value::String(v)),
422 TokenKind::Binary(v) => Ok(Value::Binary(v)),
423 TokenKind::Resource(v) => Ok(Value::Resource(v)),
424 TokenKind::Omitted => Ok(Value::Omitted),
425 TokenKind::Derived => Ok(Value::Derived),
426 TokenKind::LParen => {
427 self.at -= 1;
428 Ok(Value::List(self.parameters()?))
429 }
430 TokenKind::Name(name) => {
431 let parameters = self.parameters()?;
432 if parameters.len() != 1 {
433 return self.err("typed parameter requires one value");
434 }
435 Ok(Value::Typed(
436 name,
437 Box::new(
438 parameters
439 .into_iter()
440 .next()
441 .expect("parameter count was checked"),
442 ),
443 ))
444 }
445 _ => self.err("expected parameter value"),
446 }
447 }
448
449 fn take_name(&mut self) -> Result<String, ParseError> {
450 match self.next_kind()? {
451 TokenKind::Name(name) => Ok(name),
452 _ => self.err("expected name"),
453 }
454 }
455 fn name(&mut self, expected: &str) -> Result<(), ParseError> {
456 let actual = self.take_name()?;
457 if actual == expected {
458 Ok(())
459 } else {
460 self.err(&format!("expected {expected}, found {actual}"))
461 }
462 }
463 fn punct(&mut self, expected: &TokenKind) -> Result<(), ParseError> {
464 let actual = self.next_kind()?;
465 if std::mem::discriminant(&actual) == std::mem::discriminant(expected) {
466 Ok(())
467 } else {
468 self.err("unexpected token")
469 }
470 }
471 fn peek(&self, expected: &TokenKind) -> bool {
472 self.tokens
473 .get(self.at)
474 .is_some_and(|t| std::mem::discriminant(&t.kind) == std::mem::discriminant(expected))
475 }
476 fn peek_name(&self, expected: &str) -> bool {
477 matches!(self.tokens.get(self.at).map(|t| &t.kind), Some(TokenKind::Name(name)) if name == expected)
478 }
479 fn next_kind(&mut self) -> Result<TokenKind, ParseError> {
480 let Some(token) = self.tokens.get(self.at) else {
481 return self.err("unexpected end of input");
482 };
483 self.at += 1;
484 Ok(token.kind.clone())
485 }
486 fn current_offset(&self) -> usize {
487 self.tokens
488 .get(self.at)
489 .map_or_else(|| self.previous_end(), |t| t.span.start)
490 }
491 fn previous_end(&self) -> usize {
492 self.at
493 .checked_sub(1)
494 .and_then(|i| self.tokens.get(i))
495 .map_or(0, |t| t.span.end)
496 }
497 fn err<T>(&self, message: &str) -> Result<T, ParseError> {
498 Self::err_at(self.current_offset(), message)
499 }
500 fn err_at<T>(offset: usize, message: &str) -> Result<T, ParseError> {
501 Err(ParseError::Syntax {
502 offset,
503 message: message.into(),
504 })
505 }
506}
507
508struct AnchorResolver<'a> {
509 anchors: &'a BTreeMap<String, Value>,
510 memo: BTreeMap<String, (Value, usize)>,
511 remaining_nodes: usize,
512}
513
514impl<'a> AnchorResolver<'a> {
515 const MAX_EXPANDED_NODES: usize = 1_000_000;
516 const MAX_REFERENCE_DEPTH: usize = 256;
517
518 fn new(anchors: &'a BTreeMap<String, Value>) -> Self {
519 Self {
520 anchors,
521 memo: BTreeMap::new(),
522 remaining_nodes: Self::MAX_EXPANDED_NODES,
523 }
524 }
525
526 fn resolve_root(&mut self, value: &Value) -> Result<Value, String> {
527 let (value, _, expanded_nodes) =
528 self.resolve(value, &mut Vec::new(), self.remaining_nodes, 0)?;
529 self.remaining_nodes = self
530 .remaining_nodes
531 .checked_sub(expanded_nodes)
532 .ok_or_else(|| "aggregate expanded anchor graph exceeds 1000000 nodes".to_string())?;
533 Ok(value)
534 }
535
536 fn resolve(
537 &mut self,
538 value: &Value,
539 stack: &mut Vec<String>,
540 budget: usize,
541 depth: usize,
542 ) -> Result<(Value, usize, usize), String> {
543 if depth >= Self::MAX_REFERENCE_DEPTH {
544 return Err("expanded anchor graph exceeds its node or depth limit".into());
545 }
546 match value {
547 Value::Resource(name) if self.anchors.contains_key(name) => {
548 if let Some((value, nodes)) = self.memo.get(name) {
549 if *nodes > budget {
550 return Err("expanded anchor value exceeds 1000000 nodes".into());
551 }
552 return Ok((value.clone(), *nodes, *nodes));
553 }
554 if stack.contains(name) {
555 return Err(format!("cyclic anchor binding <{name}>"));
556 }
557 stack.push(name.clone());
558 let source = self.anchors[name].clone();
559 let resolved = self.resolve(&source, stack, budget, depth + 1);
560 stack.pop();
561 let (value, nodes, _) = resolved?;
562 if nodes > budget {
563 return Err("expanded anchor value exceeds 1000000 nodes".into());
564 }
565 self.memo.insert(name.clone(), (value.clone(), nodes));
566 Ok((value, nodes, nodes))
567 }
568 Value::List(values) => {
569 let mut nodes = 1usize;
570 let mut expanded_nodes = 0usize;
571 let mut resolved = Vec::with_capacity(values.len());
572 for value in values {
573 let remaining = budget
574 .checked_sub(expanded_nodes)
575 .ok_or_else(|| "expanded anchor value exceeds 1000000 nodes".to_string())?;
576 let (value, child_nodes, child_expanded_nodes) =
577 self.resolve(value, stack, remaining, depth + 1)?;
578 nodes = nodes
579 .checked_add(child_nodes)
580 .ok_or_else(|| "expanded anchor value exceeds 1000000 nodes".to_string())?;
581 expanded_nodes = expanded_nodes
582 .checked_add(child_expanded_nodes)
583 .ok_or_else(|| "expanded anchor value exceeds 1000000 nodes".to_string())?;
584 resolved.push(value);
585 }
586 Ok((Value::List(resolved), nodes, expanded_nodes))
587 }
588 Value::Typed(name, value) => {
589 let (value, nodes, expanded_nodes) =
590 self.resolve(value, stack, budget, depth + 1)?;
591 Ok((
592 Value::Typed(name.clone(), Box::new(value)),
593 nodes + 1,
594 expanded_nodes,
595 ))
596 }
597 value => Ok((value.clone(), 1, 0)),
598 }
599 }
600}
601
602fn references(value: &Value, out: &mut Vec<u64>) {
603 let mut pending = vec![value];
604 while let Some(value) = pending.pop() {
605 match value {
606 Value::Reference(id) => out.push(*id),
607 Value::List(values) => pending.extend(values.iter().rev()),
608 Value::Typed(_, value) => pending.push(value),
609 _ => {}
610 }
611 }
612}
613
614#[cfg(test)]
615mod tests {
616 use super::{parse, AnchorResolver, BTreeMap, Value};
617
618 #[test]
619 fn entity_index_is_not_part_of_exchange_equality() {
620 let source = b"ISO-10303-21;HEADER;ENDSEC;DATA;#1=POINT();ENDSEC;END-ISO-10303-21;";
621 let indexed = parse(source).expect("required invariant");
622 let untouched = parse(source).expect("required invariant");
623 assert_eq!(indexed.entities("POINT").count(), 1);
624 assert_eq!(indexed, untouched);
625 }
626
627 #[test]
628 fn anchor_budget_charges_only_resource_expansion() {
629 let anchors = BTreeMap::new();
630 let mut resolver = AnchorResolver::new(&anchors);
631 resolver.remaining_nodes = 0;
632
633 let ordinary = Value::List((0..1024).map(Value::Integer).collect());
634 assert_eq!(resolver.resolve_root(&ordinary), Ok(ordinary));
635 assert_eq!(resolver.remaining_nodes, 0);
636 }
637
638 #[test]
639 fn anchor_budget_still_bounds_resource_materialization() {
640 let anchors = BTreeMap::from([(
641 "a".to_string(),
642 Value::List(vec![Value::Integer(1), Value::Integer(2)]),
643 )]);
644 let mut resolver = AnchorResolver::new(&anchors);
645 resolver.remaining_nodes = 2;
646
647 assert!(resolver
648 .resolve_root(&Value::Resource("a".to_string()))
649 .is_err());
650 }
651}