meta_language/grammar/surface/
mod.rs1use std::error::Error;
10use std::fmt;
11
12use crate::grammar::Grammar;
13use crate::link_network::{Link, LinkId, LinkNetwork, LinkType};
14use crate::rust_codec::{FromLinks, LinksDecoder, LinksEncoder, ToLinks};
15use crate::ParseConfiguration;
16
17mod lower;
18mod token;
19mod write;
20
21const GRAMMAR_SURFACE_LANGUAGE: &str = "grammar-surface";
22const GRAMMAR_ROOT_TAG: &str = "grammar::grammar";
23
24#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum GrammarSurfaceError {
27 Skeleton {
29 message: String,
31 },
32 Lowering {
34 rule: Option<String>,
36 message: String,
38 },
39 UndefinedReference {
41 rule: String,
43 name: String,
45 },
46}
47
48impl fmt::Display for GrammarSurfaceError {
49 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::Skeleton { message } => write!(formatter, "grammar skeleton error: {message}"),
52 Self::Lowering { rule, message } => match rule {
53 Some(rule) => write!(formatter, "grammar lowering error in {rule}: {message}"),
54 None => write!(formatter, "grammar lowering error: {message}"),
55 },
56 Self::UndefinedReference { rule, name } => {
57 write!(formatter, "rule {rule} references undefined rule {name}")
58 }
59 }
60 }
61}
62
63impl Error for GrammarSurfaceError {}
64
65pub fn parse_grammar_surface(text: &str) -> Result<Grammar, GrammarSurfaceError> {
72 let _skeleton = skeletonise(text);
73 let tokens = token::parse_surface_tokens(text)?;
74 lower::lower_document(&tokens)
75}
76
77#[must_use]
79pub fn write_grammar_surface(grammar: &Grammar) -> String {
80 write::write_surface(grammar)
81}
82
83#[must_use]
85pub fn grammar_to_lino(grammar: &Grammar) -> String {
86 let mut encoder = LinksEncoder::new();
87 let _root = grammar.to_links(&mut encoder);
88 encoder.into_network().to_lino()
89}
90
91pub fn grammar_from_lino(text: &str) -> Result<Grammar, GrammarSurfaceError> {
98 let network = LinkNetwork::from_lino(text).map_err(|error| GrammarSurfaceError::Skeleton {
99 message: error.to_string(),
100 })?;
101 let root = grammar_root(&network).ok_or_else(|| GrammarSurfaceError::Lowering {
102 rule: None,
103 message: "LiNo network does not contain a grammar root".to_string(),
104 })?;
105 let mut decoder = LinksDecoder::new(&network);
106 Grammar::from_links(&mut decoder, root).map_err(|error| GrammarSurfaceError::Lowering {
107 rule: None,
108 message: error.to_string(),
109 })
110}
111
112fn skeletonise(text: &str) -> LinkNetwork {
113 LinkNetwork::parse(
114 text,
115 GRAMMAR_SURFACE_LANGUAGE,
116 ParseConfiguration::default(),
117 )
118}
119
120fn grammar_root(network: &LinkNetwork) -> Option<LinkId> {
121 network
122 .links()
123 .find(|link| {
124 link.metadata().link_type() == Some(LinkType::Grammar)
125 && link.metadata().term() == Some(GRAMMAR_ROOT_TAG)
126 })
127 .map(Link::id)
128}
129
130fn skeleton_error(message: impl Into<String>) -> GrammarSurfaceError {
131 GrammarSurfaceError::Skeleton {
132 message: message.into(),
133 }
134}
135
136fn lowering_error(rule: Option<&str>, message: impl Into<String>) -> GrammarSurfaceError {
137 GrammarSurfaceError::Lowering {
138 rule: rule.map(str::to_string),
139 message: message.into(),
140 }
141}