1use texform_core::parse::{self, ContextItem, ParseConfig};
2
3use crate::parse_result::ParseResult;
4
5#[derive(Clone, Debug)]
6pub struct Parser {
7 inner: parse::ParseContext,
8 default_config: ParseConfig,
9}
10
11pub struct ParserBuilder {
12 inner: parse::ParseContextBuilder,
13 default_config: ParseConfig,
14}
15
16#[derive(Debug)]
17pub struct ParserBuildError(parse::ParseContextBuildError);
18
19impl std::fmt::Display for ParserBuildError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match &self.0 {
22 parse::ParseContextBuildError::PackageLoad(error) => error.fmt(f),
23 parse::ParseContextBuildError::InvalidContextItem { name, source } => {
24 write!(f, "invalid context item {name}: {source}")
25 }
26 }
27 }
28}
29
30impl std::error::Error for ParserBuildError {}
31
32impl Parser {
33 pub fn builder() -> ParserBuilder {
34 ParserBuilder {
35 inner: parse::ParseContext::builder(),
36 default_config: ParseConfig::default(),
37 }
38 }
39
40 pub fn parse(&self, src: &str) -> ParseResult {
45 ParseResult::from_core(self.inner.parse(src, &self.default_config))
46 }
47
48 pub fn parse_with(&self, src: &str, config: &ParseConfig) -> ParseResult {
49 ParseResult::from_core(self.inner.parse(src, config))
50 }
51
52 pub fn lookup_command(
53 &self,
54 name: &str,
55 mode: parse::ContentMode,
56 ) -> Option<&parse::ActiveCommandRecord> {
57 self.inner.lookup_command(name, mode)
58 }
59
60 pub fn lookup_explicit_command(
61 &self,
62 name: &str,
63 mode: parse::ContentMode,
64 ) -> Option<&parse::ActiveCommandRecord> {
65 self.inner.lookup_explicit_command(name, mode)
66 }
67
68 pub fn lookup_character(
69 &self,
70 name: &str,
71 mode: parse::ContentMode,
72 ) -> Option<&parse::ActiveCharacterRecord> {
73 self.inner.lookup_character(name, mode)
74 }
75
76 pub fn lookup_env(
77 &self,
78 name: &str,
79 mode: parse::ContentMode,
80 ) -> Option<&parse::ActiveEnvironmentRecord> {
81 self.inner.lookup_env(name, mode)
82 }
83
84 pub fn is_delimiter_control(&self, name: &str) -> bool {
85 self.inner.is_delimiter_control(name)
86 }
87
88 pub fn knows_command_name(&self, name: &str) -> bool {
89 self.inner.knows_command_name(name)
90 }
91
92 pub fn knows_env_name(&self, name: &str) -> bool {
93 self.inner.knows_env_name(name)
94 }
95
96 pub fn knows_character_name(&self, name: &str) -> bool {
97 self.inner.knows_character_name(name)
98 }
99
100 pub(crate) fn inner(&self) -> &parse::ParseContext {
101 &self.inner
102 }
103
104 pub fn default_parse_config(&self) -> &ParseConfig {
105 &self.default_config
106 }
107}
108
109impl ParserBuilder {
110 pub fn packages(mut self, packages: &[&str]) -> Self {
111 self.inner = self.inner.packages(packages);
112 self
113 }
114
115 pub fn empty_knowledge(mut self) -> Self {
116 self.inner = parse::ParseContextBuilder::empty();
117 self
118 }
119
120 pub fn default_parse_config(mut self, config: ParseConfig) -> Self {
121 self.default_config = config;
122 self
123 }
124
125 pub fn item(mut self, item: impl Into<ContextItem>) -> Self {
126 self.inner = self.inner.insert_item(item);
127 self
128 }
129
130 pub fn insert_item(self, item: impl Into<ContextItem>) -> Self {
131 self.item(item)
132 }
133
134 pub fn remove_command(mut self, name: impl Into<String>) -> Self {
135 self.inner = self.inner.remove_command(name);
136 self
137 }
138
139 pub fn remove_environment(mut self, name: impl Into<String>) -> Self {
140 self.inner = self.inner.remove_environment(name);
141 self
142 }
143
144 pub fn remove_delimiter_control(mut self, name: impl Into<String>) -> Self {
145 self.inner = self.inner.remove_delimiter_control(name);
146 self
147 }
148
149 pub fn build(self) -> Result<Parser, ParserBuildError> {
150 Ok(Parser {
151 inner: self.inner.build().map_err(ParserBuildError)?,
152 default_config: self.default_config,
153 })
154 }
155}