1#![warn(missing_docs)]
35#![cfg_attr(docsrs, feature(doc_cfg))]
37#![no_std]
38#![forbid(unsafe_code)]
39
40extern crate alloc;
41
42mod analyze;
43mod chars;
44pub mod code;
45pub mod cst;
46mod error;
47mod lower;
48mod norm;
49mod parser;
50mod serialize;
51mod validate;
52
53use alloc::borrow::Cow;
54use alloc::vec::Vec;
55
56use mf2_model::{Diagnostic, Diagnostics, Frontend, Message, Parsed, Pattern, PatternMessage};
57
58pub use analyze::{Analysis, Name, analyze};
59pub use cst::{Cst, CstRef, Node, SyntaxKind, SyntaxNode};
60pub use error::{Error, NameRole};
61pub use serialize::serialize;
62pub use validate::validate;
63
64pub fn parse_cst(source: &str) -> Cst<'_> {
66 let mut nodes = Vec::new();
67 let mut diagnostics = Vec::new();
68 parser::parse_into(source, &mut nodes, &mut diagnostics, true);
69 Cst {
70 src: source,
71 nodes,
72 diagnostics,
73 }
74}
75
76pub fn parse_model(source: &str) -> Parsed<'_> {
82 if let Some(parsed) = simple_text(source) {
83 return parsed;
84 }
85 Parser::new().parse_model(source)
86}
87
88#[derive(Clone, Debug, Default)]
91pub struct Parser {
92 nodes: Vec<Node>,
93 diagnostics: Vec<Diagnostic>,
94}
95
96impl Parser {
97 pub const fn new() -> Self {
99 Parser {
100 nodes: Vec::new(),
101 diagnostics: Vec::new(),
102 }
103 }
104
105 pub fn with_capacity(nodes: usize) -> Self {
107 Parser {
108 nodes: Vec::with_capacity(nodes),
109 diagnostics: Vec::new(),
110 }
111 }
112
113 pub fn parse_cst<'p, 'src>(&'p mut self, source: &'src str) -> CstRef<'p, 'src> {
115 parser::parse_into(source, &mut self.nodes, &mut self.diagnostics, true);
116 CstRef {
117 src: source,
118 nodes: &self.nodes,
119 diagnostics: &self.diagnostics,
120 }
121 }
122
123 pub fn parse_model<'src>(&mut self, source: &'src str) -> Parsed<'src> {
125 if let Some(parsed) = simple_text(source) {
126 return parsed;
127 }
128 parser::parse_into(source, &mut self.nodes, &mut self.diagnostics, false);
129 if !self.diagnostics.is_empty() || self.nodes.is_empty() {
130 return Parsed {
131 message: None,
132 diagnostics: Diagnostics::from(core::mem::take(&mut self.diagnostics)),
133 };
134 }
135 model_from_arena(source, &self.nodes)
136 }
137}
138
139impl Frontend for Parser {
140 fn parse<'src>(&mut self, source: &'src str) -> Parsed<'src> {
141 self.parse_model(source)
142 }
143}
144
145fn simple_text(source: &str) -> Option<Parsed<'_>> {
149 let b = source.as_bytes();
150 if chars::find_text_end(b, 0) != b.len() {
151 return None;
152 }
153 let mut i = 0;
154 while let Some((n, _)) = chars::trivia_at(b, i) {
155 i += n;
156 }
157 if b.get(i) == Some(&b'.') {
158 return None;
159 }
160 Some(Parsed {
161 message: Some(Message::Pattern(PatternMessage {
162 declarations: Vec::new(),
163 pattern: Pattern::from_text(Cow::Borrowed(source)),
164 })),
165 diagnostics: Diagnostics::new(),
166 })
167}
168
169pub(crate) fn model_from_arena<'src>(source: &'src str, nodes: &[Node]) -> Parsed<'src> {
172 let arena = lower::Arena { src: source, nodes };
173 let message = arena.message();
174 let mut found = Vec::new();
175 validate::check(&message, &mut |kind, code, loc| {
176 found.push((kind, code, loc));
177 });
178 if found.is_empty() {
179 return Parsed {
180 message: Some(message),
181 diagnostics: Diagnostics::new(),
182 };
183 }
184 let mut locator = lower::Locator::new(&arena);
185 let mut diagnostics: Vec<Diagnostic> = found
186 .iter()
187 .map(|(kind, code, loc)| Diagnostic::new(*kind, *code, locator.resolve(loc)))
188 .collect();
189 diagnostics.sort_by_key(|d| d.span.map_or(0, |s| s.start));
191 Parsed {
192 message: Some(message),
193 diagnostics: Diagnostics::from(diagnostics),
194 }
195}