1use std::char;
2
3use crate::grammar::interchange::{
4 parse_native_expression, parse_native_grammar, render_native_expression, render_native_grammar,
5};
6use crate::grammar::{
7 CharClassItem, Grammar, GrammarExpr, GrammarFormat, GrammarRule, RuleAttributes, RuleKind,
8};
9use crate::link_network::{Link, LinkId, LinkMetadata, LinkNetwork, LinkType};
10use crate::rust_codec::{FromLinks, LinksCodecError, LinksDecoder, LinksEncoder, ToLinks};
11
12const GRAMMAR: &str = "grammar::grammar";
13const RULE: &str = "grammar::rule";
14
15const EXPR_EMPTY: &str = "grammar::expression::empty-expression";
16const EXPR_TERMINAL: &str = "grammar::expression::terminal";
17const EXPR_TERMINAL_INSENSITIVE: &str = "grammar::expression::case-insensitive-terminal";
18const EXPR_CHAR_RANGE: &str = "grammar::expression::character-range";
19const EXPR_CHAR_CLASS: &str = "grammar::expression::character-class";
20const EXPR_ANY_CHAR: &str = "grammar::expression::any-character";
21const EXPR_NON_TERMINAL: &str = "grammar::expression::nonterminal";
22const EXPR_CHOICE: &str = "grammar::expression::choice";
23const EXPR_SEQUENCE: &str = "grammar::expression::sequence";
24const EXPR_OPTIONAL: &str = "grammar::expression::optional-expression";
25const EXPR_ZERO_OR_MORE: &str = "grammar::expression::zero-or-more-repetition";
26const EXPR_ONE_OR_MORE: &str = "grammar::expression::one-or-more-repetition";
27const EXPR_REPEAT: &str = "grammar::expression::counted-repetition";
28const EXPR_AND: &str = "grammar::expression::positive-predicate";
29const EXPR_NOT: &str = "grammar::expression::negative-predicate";
30const EXPR_CAPTURE: &str = "grammar::expression::capture";
31const EXPR_FEATURE: &str = "grammar::expression::feature-union-form";
33
34const CHAR_CLASS_CHAR: &str = "grammar::character-class-item::character";
35const CHAR_CLASS_RANGE: &str = "grammar::character-class-item::character-range";
36
37const VALUE_NONE: &str = "grammar::value::absent-value";
38const VALUE_SOME: &str = "grammar::value::present-value";
39const VALUE_STRING_PREFIX: &str = "grammar::value::string::";
40const VALUE_CHAR_PREFIX: &str = "grammar::value::character::";
41const VALUE_BOOL_PREFIX: &str = "grammar::value::boolean-value::";
42const VALUE_USIZE_PREFIX: &str = "grammar::value::natural-number::";
43const VALUE_RULE_KIND_PREFIX: &str = "grammar::value::rule-kind::";
44const VALUE_FORMAT_PREFIX: &str = "grammar::value::format::";
45
46const FORMER_GRAMMAR_TAGS: &[(&str, &str)] = &[
49 ("grammar::expr::empty", EXPR_EMPTY),
50 ("grammar::expr::terminal", EXPR_TERMINAL),
51 (
52 "grammar::expr::terminal-insensitive",
53 EXPR_TERMINAL_INSENSITIVE,
54 ),
55 ("grammar::expr::char-range", EXPR_CHAR_RANGE),
56 ("grammar::expr::char-class", EXPR_CHAR_CLASS),
57 ("grammar::expr::any-char", EXPR_ANY_CHAR),
58 ("grammar::expr::non-terminal", EXPR_NON_TERMINAL),
59 ("grammar::expr::choice", EXPR_CHOICE),
60 ("grammar::expr::sequence", EXPR_SEQUENCE),
61 ("grammar::expr::optional", EXPR_OPTIONAL),
62 ("grammar::expr::zero-or-more", EXPR_ZERO_OR_MORE),
63 ("grammar::expr::one-or-more", EXPR_ONE_OR_MORE),
64 ("grammar::expr::repeat", EXPR_REPEAT),
65 ("grammar::expr::and", EXPR_AND),
66 ("grammar::expr::not", EXPR_NOT),
67 ("grammar::expr::capture", EXPR_CAPTURE),
68 ("grammar::char-class-item::char", CHAR_CLASS_CHAR),
69 ("grammar::char-class-item::range", CHAR_CLASS_RANGE),
70 ("grammar::value::none", VALUE_NONE),
71 ("grammar::value::some", VALUE_SOME),
72];
73
74const FORMER_VALUE_PREFIXES: &[(&str, &str)] = &[
77 ("grammar::value::char::", VALUE_CHAR_PREFIX),
78 ("grammar::value::bool::", VALUE_BOOL_PREFIX),
79 ("grammar::value::usize::", VALUE_USIZE_PREFIX),
80];
81
82fn current_grammar_tag(term: &str) -> &str {
84 FORMER_GRAMMAR_TAGS
85 .iter()
86 .find(|(former, _)| *former == term)
87 .map_or(term, |(_, current)| current)
88}
89
90impl ToLinks for Grammar {
91 fn to_links(&self, encoder: &mut LinksEncoder) -> LinkId {
92 encode_grammar(encoder.network_mut(), self)
93 }
94}
95
96impl FromLinks for Grammar {
97 fn from_links(decoder: &mut LinksDecoder<'_>, link: LinkId) -> Result<Self, LinksCodecError> {
98 decode_grammar(decoder.network(), link)
99 }
100}
101
102fn encode_grammar(network: &mut LinkNetwork, grammar: &Grammar) -> LinkId {
103 let mut references = Vec::with_capacity(grammar.rules().len() + 2);
104 references.push(encode_option_format(network, grammar.source_format()));
105 references.push(encode_option_string(network, grammar.start()));
106 references.extend(
107 grammar
108 .rules()
109 .iter()
110 .map(|rule| encode_rule(network, rule)),
111 );
112 insert_grammar_node(network, GRAMMAR, &references)
113}
114
115fn decode_grammar(network: &LinkNetwork, link: LinkId) -> Result<Grammar, LinksCodecError> {
116 let references = expect_tag(network, link, GRAMMAR)?;
117 if references.len() < 2 {
118 return Err(malformed(
119 link,
120 "grammar links must contain source format and start references",
121 ));
122 }
123
124 let source_format = decode_option_format(network, references[0])?;
125 let start = decode_option_string(network, references[1])?;
126 let mut grammar = Grammar::new();
127 if let Some(source_format) = source_format {
128 grammar = grammar.with_source_format(source_format);
129 }
130 if let Some(start) = start {
131 grammar = grammar.with_start(start);
132 }
133
134 for rule in &references[2..] {
135 grammar.add_rule(decode_rule(network, *rule)?);
136 }
137 Ok(grammar)
138}
139
140fn encode_rule(network: &mut LinkNetwork, rule: &GrammarRule) -> LinkId {
141 let expr = encode_expr(network, rule.expr());
142 let mut references = vec![
143 encode_string_value(network, rule.name()),
144 expr,
145 encode_rule_kind_value(network, rule.kind()),
146 encode_option_string(network, rule.concept()),
147 encode_option_string(network, rule.doc()),
148 ];
149 if !rule.attributes.is_empty() {
152 let carrier = Grammar::new().with_start(ATTRIBUTE_CARRIER).with_rule(
153 GrammarRule::new(ATTRIBUTE_CARRIER, GrammarExpr::Empty)
154 .with_attributes(rule.attributes.clone()),
155 );
156 references.push(encode_string_value(
157 network,
158 &render_native_grammar(&carrier),
159 ));
160 }
161 insert_grammar_node(network, RULE, &references)
162}
163
164const ATTRIBUTE_CARRIER: &str = "attributes";
166
167fn decode_rule_attributes(
168 network: &LinkNetwork,
169 link: LinkId,
170) -> Result<RuleAttributes, LinksCodecError> {
171 let listing = decode_string_value(network, link)?;
172 parse_native_grammar(&listing)
173 .ok()
174 .and_then(|carrier| carrier.rules().first().map(|rule| rule.attributes.clone()))
175 .ok_or_else(|| malformed(link, "rule attributes must be a native rule listing"))
176}
177
178fn decode_rule(network: &LinkNetwork, link: LinkId) -> Result<GrammarRule, LinksCodecError> {
179 let references = expect_tag(network, link, RULE)?;
180 let (fields, attributes) = match references {
181 [fields @ .., attributes] if references.len() == 6 => (fields, Some(*attributes)),
182 fields => (fields, None),
183 };
184 let [name, expr, kind, concept, doc] = fields else {
185 return Err(malformed(
186 link,
187 "rule links must contain name, expression, kind, concept, and doc references, and may add attributes",
188 ));
189 };
190 let mut rule = GrammarRule::new(
191 decode_string_value(network, *name)?,
192 decode_expr(network, *expr)?,
193 )
194 .with_kind(decode_rule_kind_value(network, *kind)?);
195 if let Some(concept) = decode_option_string(network, *concept)? {
196 rule = rule.with_concept(concept);
197 }
198 if let Some(doc) = decode_option_string(network, *doc)? {
199 rule = rule.with_doc(doc);
200 }
201 if let Some(attributes) = attributes {
202 rule = rule.with_attributes(decode_rule_attributes(network, attributes)?);
203 }
204 Ok(rule)
205}
206
207fn encode_expr(network: &mut LinkNetwork, expr: &GrammarExpr) -> LinkId {
208 match expr {
209 GrammarExpr::Empty => insert_grammar_node(network, EXPR_EMPTY, &[]),
210 GrammarExpr::Terminal(value) => {
211 let references = [encode_string_value(network, value)];
212 insert_grammar_node(network, EXPR_TERMINAL, &references)
213 }
214 GrammarExpr::TerminalInsensitive(value) => {
215 let references = [encode_string_value(network, value)];
216 insert_grammar_node(network, EXPR_TERMINAL_INSENSITIVE, &references)
217 }
218 GrammarExpr::CharRange(start, end) => {
219 let references = [
220 encode_char_value(network, *start),
221 encode_char_value(network, *end),
222 ];
223 insert_grammar_node(network, EXPR_CHAR_RANGE, &references)
224 }
225 GrammarExpr::CharClass { negated, items } => {
226 let mut references = Vec::with_capacity(items.len() + 1);
227 references.push(encode_bool_value(network, *negated));
228 references.extend(
229 items
230 .iter()
231 .map(|item| encode_char_class_item(network, item)),
232 );
233 insert_grammar_node(network, EXPR_CHAR_CLASS, &references)
234 }
235 GrammarExpr::AnyChar => insert_grammar_node(network, EXPR_ANY_CHAR, &[]),
236 GrammarExpr::NonTerminal(value) => {
237 let references = [encode_string_value(network, value)];
238 insert_grammar_node(network, EXPR_NON_TERMINAL, &references)
239 }
240 GrammarExpr::Choice {
241 ordered,
242 alternatives,
243 } => {
244 let mut references = Vec::with_capacity(alternatives.len() + 1);
245 references.push(encode_bool_value(network, *ordered));
246 references.extend(
247 alternatives
248 .iter()
249 .map(|alternative| encode_expr(network, alternative)),
250 );
251 insert_grammar_node(network, EXPR_CHOICE, &references)
252 }
253 GrammarExpr::Sequence(items) => {
254 let references = items
255 .iter()
256 .map(|item| encode_expr(network, item))
257 .collect::<Vec<_>>();
258 insert_grammar_node(network, EXPR_SEQUENCE, &references)
259 }
260 GrammarExpr::Optional(expr) => encode_unary_expr(network, EXPR_OPTIONAL, expr),
261 GrammarExpr::ZeroOrMore(expr) => encode_unary_expr(network, EXPR_ZERO_OR_MORE, expr),
262 GrammarExpr::OneOrMore(expr) => encode_unary_expr(network, EXPR_ONE_OR_MORE, expr),
263 GrammarExpr::Repeat { expr, min, max } => {
264 let references = [
265 encode_expr(network, expr),
266 encode_usize_value(network, *min),
267 encode_option_usize(network, *max),
268 ];
269 insert_grammar_node(network, EXPR_REPEAT, &references)
270 }
271 GrammarExpr::And(expr) => encode_unary_expr(network, EXPR_AND, expr),
272 GrammarExpr::Not(expr) => encode_unary_expr(network, EXPR_NOT, expr),
273 GrammarExpr::Capture { label, expr } => {
274 let references = [
275 encode_option_string(network, label.as_deref()),
276 encode_expr(network, expr),
277 ];
278 insert_grammar_node(network, EXPR_CAPTURE, &references)
279 }
280 GrammarExpr::Feature(_) => {
281 let references = [encode_string_value(
282 network,
283 &render_native_expression(expr),
284 )];
285 insert_grammar_node(network, EXPR_FEATURE, &references)
286 }
287 }
288}
289
290fn decode_expr(network: &LinkNetwork, link: LinkId) -> Result<GrammarExpr, LinksCodecError> {
291 let (term, references) = grammar_link(network, link)?;
292 match term {
293 EXPR_EMPTY => {
294 expect_count(link, references, 0)?;
295 Ok(GrammarExpr::Empty)
296 }
297 EXPR_TERMINAL => {
298 let [value] = references else {
299 return Err(expected_count(link, 1, references.len()));
300 };
301 Ok(GrammarExpr::Terminal(decode_string_value(network, *value)?))
302 }
303 EXPR_TERMINAL_INSENSITIVE => {
304 let [value] = references else {
305 return Err(expected_count(link, 1, references.len()));
306 };
307 Ok(GrammarExpr::TerminalInsensitive(decode_string_value(
308 network, *value,
309 )?))
310 }
311 EXPR_CHAR_RANGE => {
312 let [start, end] = references else {
313 return Err(expected_count(link, 2, references.len()));
314 };
315 Ok(GrammarExpr::CharRange(
316 decode_char_value(network, *start)?,
317 decode_char_value(network, *end)?,
318 ))
319 }
320 EXPR_CHAR_CLASS => {
321 let Some((negated, items)) = references.split_first() else {
322 return Err(malformed(
323 link,
324 "character class links must contain the negated flag",
325 ));
326 };
327 Ok(GrammarExpr::CharClass {
328 negated: decode_bool_value(network, *negated)?,
329 items: items
330 .iter()
331 .map(|item| decode_char_class_item(network, *item))
332 .collect::<Result<Vec<_>, _>>()?,
333 })
334 }
335 EXPR_ANY_CHAR => {
336 expect_count(link, references, 0)?;
337 Ok(GrammarExpr::AnyChar)
338 }
339 EXPR_NON_TERMINAL => {
340 let [value] = references else {
341 return Err(expected_count(link, 1, references.len()));
342 };
343 Ok(GrammarExpr::NonTerminal(decode_string_value(
344 network, *value,
345 )?))
346 }
347 EXPR_CHOICE => {
348 let Some((ordered, alternatives)) = references.split_first() else {
349 return Err(malformed(
350 link,
351 "choice links must contain the ordered flag",
352 ));
353 };
354 Ok(GrammarExpr::Choice {
355 ordered: decode_bool_value(network, *ordered)?,
356 alternatives: alternatives
357 .iter()
358 .map(|alternative| decode_expr(network, *alternative))
359 .collect::<Result<Vec<_>, _>>()?,
360 })
361 }
362 EXPR_SEQUENCE => Ok(GrammarExpr::Sequence(
363 references
364 .iter()
365 .map(|item| decode_expr(network, *item))
366 .collect::<Result<Vec<_>, _>>()?,
367 )),
368 EXPR_OPTIONAL => decode_unary_expr(network, link, references).map(GrammarExpr::optional),
369 EXPR_ZERO_OR_MORE => {
370 decode_unary_expr(network, link, references).map(GrammarExpr::zero_or_more)
371 }
372 EXPR_ONE_OR_MORE => {
373 decode_unary_expr(network, link, references).map(GrammarExpr::one_or_more)
374 }
375 EXPR_REPEAT => {
376 let [expr, min, max] = references else {
377 return Err(expected_count(link, 3, references.len()));
378 };
379 Ok(GrammarExpr::repeat(
380 decode_expr(network, *expr)?,
381 decode_usize_value(network, *min)?,
382 decode_option_usize(network, *max)?,
383 ))
384 }
385 EXPR_AND => decode_unary_expr(network, link, references).map(GrammarExpr::and),
386 EXPR_NOT => decode_unary_expr(network, link, references).map(GrammarExpr::not),
387 EXPR_CAPTURE => {
388 let [label, expr] = references else {
389 return Err(expected_count(link, 2, references.len()));
390 };
391 Ok(GrammarExpr::Capture {
392 label: decode_option_string(network, *label)?,
393 expr: Box::new(decode_expr(network, *expr)?),
394 })
395 }
396 EXPR_FEATURE => {
397 let [text] = references else {
398 return Err(expected_count(link, 1, references.len()));
399 };
400 parse_native_expression(&decode_string_value(network, *text)?)
401 .map_err(|error| malformed(link, error.to_string()))
402 }
403 _ => Err(malformed(
404 link,
405 format!("unexpected grammar expression tag {term:?}"),
406 )),
407 }
408}
409
410fn encode_unary_expr(network: &mut LinkNetwork, tag: &str, expr: &GrammarExpr) -> LinkId {
411 let references = [encode_expr(network, expr)];
412 insert_grammar_node(network, tag, &references)
413}
414
415fn decode_unary_expr(
416 network: &LinkNetwork,
417 link: LinkId,
418 references: &[LinkId],
419) -> Result<GrammarExpr, LinksCodecError> {
420 let [expr] = references else {
421 return Err(expected_count(link, 1, references.len()));
422 };
423 decode_expr(network, *expr)
424}
425
426fn encode_char_class_item(network: &mut LinkNetwork, item: &CharClassItem) -> LinkId {
427 match item {
428 CharClassItem::Char(value) => {
429 let references = [encode_char_value(network, *value)];
430 insert_grammar_node(network, CHAR_CLASS_CHAR, &references)
431 }
432 CharClassItem::Range(start, end) => {
433 let references = [
434 encode_char_value(network, *start),
435 encode_char_value(network, *end),
436 ];
437 insert_grammar_node(network, CHAR_CLASS_RANGE, &references)
438 }
439 }
440}
441
442fn decode_char_class_item(
443 network: &LinkNetwork,
444 link: LinkId,
445) -> Result<CharClassItem, LinksCodecError> {
446 let (term, references) = grammar_link(network, link)?;
447 match term {
448 CHAR_CLASS_CHAR => {
449 let [value] = references else {
450 return Err(expected_count(link, 1, references.len()));
451 };
452 Ok(CharClassItem::Char(decode_char_value(network, *value)?))
453 }
454 CHAR_CLASS_RANGE => {
455 let [start, end] = references else {
456 return Err(expected_count(link, 2, references.len()));
457 };
458 Ok(CharClassItem::Range(
459 decode_char_value(network, *start)?,
460 decode_char_value(network, *end)?,
461 ))
462 }
463 _ => Err(malformed(
464 link,
465 format!("unexpected character class item tag {term:?}"),
466 )),
467 }
468}
469
470fn encode_option_string(network: &mut LinkNetwork, value: Option<&str>) -> LinkId {
471 match value {
472 Some(value) => {
473 let references = [encode_string_value(network, value)];
474 insert_grammar_node(network, VALUE_SOME, &references)
475 }
476 None => insert_grammar_node(network, VALUE_NONE, &[]),
477 }
478}
479
480fn decode_option_string(
481 network: &LinkNetwork,
482 link: LinkId,
483) -> Result<Option<String>, LinksCodecError> {
484 decode_option(network, link, decode_string_value)
485}
486
487fn encode_option_usize(network: &mut LinkNetwork, value: Option<usize>) -> LinkId {
488 match value {
489 Some(value) => {
490 let references = [encode_usize_value(network, value)];
491 insert_grammar_node(network, VALUE_SOME, &references)
492 }
493 None => insert_grammar_node(network, VALUE_NONE, &[]),
494 }
495}
496
497fn decode_option_usize(
498 network: &LinkNetwork,
499 link: LinkId,
500) -> Result<Option<usize>, LinksCodecError> {
501 decode_option(network, link, decode_usize_value)
502}
503
504fn encode_option_format(network: &mut LinkNetwork, value: Option<GrammarFormat>) -> LinkId {
505 match value {
506 Some(value) => {
507 let references = [encode_format_value(network, value)];
508 insert_grammar_node(network, VALUE_SOME, &references)
509 }
510 None => insert_grammar_node(network, VALUE_NONE, &[]),
511 }
512}
513
514fn decode_option_format(
515 network: &LinkNetwork,
516 link: LinkId,
517) -> Result<Option<GrammarFormat>, LinksCodecError> {
518 decode_option(network, link, decode_format_value)
519}
520
521fn decode_option<T>(
522 network: &LinkNetwork,
523 link: LinkId,
524 decode_value: fn(&LinkNetwork, LinkId) -> Result<T, LinksCodecError>,
525) -> Result<Option<T>, LinksCodecError> {
526 let (term, references) = grammar_link(network, link)?;
527 match term {
528 VALUE_NONE => {
529 expect_count(link, references, 0)?;
530 Ok(None)
531 }
532 VALUE_SOME => {
533 let [value] = references else {
534 return Err(expected_count(link, 1, references.len()));
535 };
536 decode_value(network, *value).map(Some)
537 }
538 _ => Err(malformed(
539 link,
540 format!("expected optional value tag, found {term:?}"),
541 )),
542 }
543}
544
545fn encode_string_value(network: &mut LinkNetwork, value: &str) -> LinkId {
546 insert_grammar_value(
547 network,
548 &format!("{VALUE_STRING_PREFIX}{}", hex_encode(value)),
549 )
550}
551
552fn decode_string_value(network: &LinkNetwork, link: LinkId) -> Result<String, LinksCodecError> {
553 let value = prefixed_value(network, link, VALUE_STRING_PREFIX, "String")?;
554 hex_decode(link, "String", value)
555}
556
557fn encode_char_value(network: &mut LinkNetwork, value: char) -> LinkId {
558 insert_grammar_value(
559 network,
560 &format!("{VALUE_CHAR_PREFIX}{:x}", u32::from(value)),
561 )
562}
563
564fn decode_char_value(network: &LinkNetwork, link: LinkId) -> Result<char, LinksCodecError> {
565 let value = prefixed_value(network, link, VALUE_CHAR_PREFIX, "char")?;
566 let code = u32::from_str_radix(value, 16)
567 .map_err(|error| invalid_value(link, "char", Some(value), &error.to_string()))?;
568 char::from_u32(code).ok_or_else(|| invalid_value(link, "char", Some(value), "invalid char"))
569}
570
571fn encode_bool_value(network: &mut LinkNetwork, value: bool) -> LinkId {
572 insert_grammar_value(network, &format!("{VALUE_BOOL_PREFIX}{value}"))
573}
574
575fn decode_bool_value(network: &LinkNetwork, link: LinkId) -> Result<bool, LinksCodecError> {
576 let value = prefixed_value(network, link, VALUE_BOOL_PREFIX, "bool")?;
577 value.parse().map_err(|error: std::str::ParseBoolError| {
578 invalid_value(link, "bool", Some(value), &error.to_string())
579 })
580}
581
582fn encode_usize_value(network: &mut LinkNetwork, value: usize) -> LinkId {
583 insert_grammar_value(network, &format!("{VALUE_USIZE_PREFIX}{value}"))
584}
585
586fn decode_usize_value(network: &LinkNetwork, link: LinkId) -> Result<usize, LinksCodecError> {
587 let value = prefixed_value(network, link, VALUE_USIZE_PREFIX, "usize")?;
588 value.parse().map_err(|error: std::num::ParseIntError| {
589 invalid_value(link, "usize", Some(value), &error.to_string())
590 })
591}
592
593fn encode_rule_kind_value(network: &mut LinkNetwork, value: RuleKind) -> LinkId {
594 insert_grammar_value(
595 network,
596 &format!("{VALUE_RULE_KIND_PREFIX}{}", value.as_str()),
597 )
598}
599
600fn decode_rule_kind_value(
601 network: &LinkNetwork,
602 link: LinkId,
603) -> Result<RuleKind, LinksCodecError> {
604 let value = prefixed_value(network, link, VALUE_RULE_KIND_PREFIX, "RuleKind")?;
605 RuleKind::from_tag(value)
606 .ok_or_else(|| invalid_value(link, "RuleKind", Some(value), "unknown rule kind"))
607}
608
609fn encode_format_value(network: &mut LinkNetwork, value: GrammarFormat) -> LinkId {
610 insert_grammar_value(network, &format!("{VALUE_FORMAT_PREFIX}{}", value.as_str()))
611}
612
613fn decode_format_value(
614 network: &LinkNetwork,
615 link: LinkId,
616) -> Result<GrammarFormat, LinksCodecError> {
617 let value = prefixed_value(network, link, VALUE_FORMAT_PREFIX, "GrammarFormat")?;
618 GrammarFormat::from_tag(value)
619 .ok_or_else(|| invalid_value(link, "GrammarFormat", Some(value), "unknown grammar format"))
620}
621
622fn insert_grammar_node(network: &mut LinkNetwork, term: &str, references: &[LinkId]) -> LinkId {
623 network.insert_dynamic_link(
624 references,
625 LinkMetadata::new()
626 .with_link_type(LinkType::Grammar)
627 .with_term(term),
628 )
629}
630
631fn insert_grammar_value(network: &mut LinkNetwork, term: &str) -> LinkId {
632 insert_grammar_node(network, term, &[])
633}
634
635fn expect_tag<'network>(
636 network: &'network LinkNetwork,
637 link: LinkId,
638 expected: &str,
639) -> Result<&'network [LinkId], LinksCodecError> {
640 let (term, references) = grammar_link(network, link)?;
641 if term == expected {
642 Ok(references)
643 } else {
644 Err(malformed(
645 link,
646 format!("expected grammar tag {expected:?}, found {term:?}"),
647 ))
648 }
649}
650
651fn grammar_link(network: &LinkNetwork, link: LinkId) -> Result<(&str, &[LinkId]), LinksCodecError> {
652 let link = network
653 .link(link)
654 .ok_or(LinksCodecError::MissingLink(link))?;
655 expect_grammar_type(link)?;
656 let Some(term) = link.metadata().term() else {
657 return Err(malformed(link.id(), "grammar link is missing its term tag"));
658 };
659 Ok((current_grammar_tag(term), link.references()))
660}
661
662fn expect_grammar_type(link: &Link) -> Result<(), LinksCodecError> {
663 if link.metadata().link_type() == Some(LinkType::Grammar) {
664 return Ok(());
665 }
666 Err(malformed(
667 link.id(),
668 format!(
669 "expected LinkType::Grammar, found {:?}",
670 link.metadata().link_type()
671 ),
672 ))
673}
674
675fn prefixed_value<'network>(
676 network: &'network LinkNetwork,
677 link: LinkId,
678 prefix: &str,
679 type_name: &str,
680) -> Result<&'network str, LinksCodecError> {
681 let (term, _) = grammar_link(network, link)?;
682 term.strip_prefix(prefix)
683 .or_else(|| {
684 FORMER_VALUE_PREFIXES
685 .iter()
686 .filter(|(_, current)| *current == prefix)
687 .find_map(|(former, _)| term.strip_prefix(former))
688 })
689 .ok_or_else(|| invalid_value(link, type_name, Some(term), "wrong value prefix"))
690}
691
692fn expect_count(
693 link: LinkId,
694 references: &[LinkId],
695 expected: usize,
696) -> Result<(), LinksCodecError> {
697 if references.len() == expected {
698 Ok(())
699 } else {
700 Err(expected_count(link, expected, references.len()))
701 }
702}
703
704fn expected_count(link: LinkId, expected: usize, actual: usize) -> LinksCodecError {
705 malformed(
706 link,
707 format!("expected {expected} references, found {actual}"),
708 )
709}
710
711fn malformed(link: LinkId, reason: impl Into<String>) -> LinksCodecError {
712 LinksCodecError::MalformedObject {
713 object: link,
714 reason: reason.into(),
715 }
716}
717
718fn invalid_value(
719 link: LinkId,
720 type_name: &str,
721 value: Option<&str>,
722 reason: &str,
723) -> LinksCodecError {
724 LinksCodecError::InvalidLiteral {
725 object: link,
726 type_name: type_name.to_string(),
727 value: value.map(ToString::to_string),
728 reason: reason.to_string(),
729 }
730}
731
732fn hex_encode(value: &str) -> String {
733 const HEX: &[u8; 16] = b"0123456789abcdef";
734 let mut output = String::with_capacity(value.len() * 2);
735 for byte in value.as_bytes() {
736 output.push(HEX[(byte >> 4) as usize] as char);
737 output.push(HEX[(byte & 0x0f) as usize] as char);
738 }
739 output
740}
741
742fn hex_decode(link: LinkId, type_name: &str, value: &str) -> Result<String, LinksCodecError> {
743 if !value.len().is_multiple_of(2) {
744 return Err(invalid_value(
745 link,
746 type_name,
747 Some(value),
748 "hex payload has odd length",
749 ));
750 }
751
752 let mut bytes = Vec::with_capacity(value.len() / 2);
753 for pair in value.as_bytes().as_chunks::<2>().0 {
754 let high = hex_digit(pair[0])
755 .ok_or_else(|| invalid_value(link, type_name, Some(value), "invalid hex digit"))?;
756 let low = hex_digit(pair[1])
757 .ok_or_else(|| invalid_value(link, type_name, Some(value), "invalid hex digit"))?;
758 bytes.push((high << 4) | low);
759 }
760
761 String::from_utf8(bytes).map_err(|error| {
762 invalid_value(
763 link,
764 type_name,
765 Some(value),
766 &format!("invalid UTF-8: {error}"),
767 )
768 })
769}
770
771const fn hex_digit(value: u8) -> Option<u8> {
772 match value {
773 b'0'..=b'9' => Some(value - b'0'),
774 b'a'..=b'f' => Some(value - b'a' + 10),
775 b'A'..=b'F' => Some(value - b'A' + 10),
776 _ => None,
777 }
778}