fea_rs/compile/
compiler.rs1use std::{
4 io::Write,
5 path::{Path, PathBuf},
6};
7
8use crate::{
9 parse::{FileSystemResolver, SourceResolver},
10 DiagnosticSet, GlyphMap,
11};
12
13use super::{error::CompilerError, Compilation, FeatureProvider, Opts, VariationInfo};
14
15const DEFAULT_N_MESSAGES_TO_PRINT: usize = 100;
16
17pub struct Compiler<'a, F: FeatureProvider, V: VariationInfo> {
30 root_path: PathBuf,
31 project_root: Option<PathBuf>,
32 glyph_map: &'a GlyphMap,
33 var_info: Option<&'a V>,
35 feature_writer: Option<&'a F>,
36 print_warnings: bool,
39 max_n_errors: usize,
40 opts: Opts,
41 resolver: Option<Box<dyn SourceResolver>>,
42}
43
44impl<'a, F: FeatureProvider, V: VariationInfo> Compiler<'a, F, V> {
45 pub fn new(root_path: impl Into<PathBuf>, glyph_map: &'a GlyphMap) -> Self {
54 Compiler {
55 root_path: root_path.into(),
56 glyph_map,
57 var_info: None,
58 feature_writer: None,
59 opts: Default::default(),
60 print_warnings: false,
61 resolver: Default::default(),
62 project_root: Default::default(),
63 max_n_errors: DEFAULT_N_MESSAGES_TO_PRINT,
64 }
65 }
66
67 pub fn with_resolver(mut self, resolver: impl SourceResolver + 'static) -> Self {
69 self.resolver = Some(Box::new(resolver));
70 self
71 }
72
73 pub fn with_variable_info(mut self, var_info: &'a V) -> Self {
75 self.var_info = Some(var_info);
76 self
77 }
78
79 pub fn with_feature_writer(mut self, feature_writer: &'a F) -> Self {
81 self.feature_writer = Some(feature_writer);
82 self
83 }
84
85 #[deprecated(since = "0.14.1", note = "use print_warnings method instead")]
89 pub fn verbose(self, verbose: bool) -> Self {
90 self.print_warnings(verbose)
91 }
92
93 pub fn print_warnings(mut self, warnings: bool) -> Self {
95 self.print_warnings = warnings;
96 self
97 }
98
99 pub fn with_project_root(mut self, project_root: impl Into<PathBuf>) -> Self {
104 self.project_root = Some(project_root.into());
105 self
106 }
107
108 pub fn with_opts(mut self, opts: Opts) -> Self {
110 self.opts = opts;
111 self
112 }
113
114 pub fn compile(self) -> Result<Compilation, CompilerError> {
122 let resolver = self.resolver.unwrap_or_else(|| {
123 let project_root = self.project_root.unwrap_or_else(|| {
124 Path::new(&self.root_path)
125 .parent()
126 .map(PathBuf::from)
127 .unwrap_or_default()
128 });
129 Box::new(FileSystemResolver::new(project_root))
130 });
131
132 let (tree, diagnostics) =
133 crate::parse::ParseContext::parse(self.root_path, Some(self.glyph_map), resolver)?
134 .generate_parse_tree();
135 print_warnings_return_errors(diagnostics, self.print_warnings, self.max_n_errors)
136 .map_err(CompilerError::ParseFail)?;
137 let diagnostics = super::validate(&tree, self.glyph_map, self.var_info);
138 print_warnings_return_errors(diagnostics, self.print_warnings, self.max_n_errors)
139 .map_err(CompilerError::ValidationFail)?;
140 let mut ctx = super::CompilationCtx::new(
141 self.glyph_map,
142 tree.source_map(),
143 self.var_info,
144 self.feature_writer,
145 self.opts,
146 );
147 ctx.compile(&tree.typed_root());
148
149 let messages = std::mem::take(&mut ctx.errors);
152 let diagnostics = DiagnosticSet::new(messages, &tree, self.max_n_errors);
153 print_warnings_return_errors(diagnostics, self.print_warnings, self.max_n_errors)
154 .map_err(CompilerError::CompilationFail)?;
155 Ok(ctx.build().unwrap().0) }
157
158 pub fn compile_binary(self) -> Result<Vec<u8>, CompilerError> {
160 let glyph_map = self.glyph_map;
161 Ok(self.compile()?.to_binary(glyph_map)?)
162 }
163}
164
165fn print_warnings_return_errors(
166 mut diagnostics: DiagnosticSet,
167 print_warnings: bool,
168 max_to_print: usize,
169) -> Result<(), DiagnosticSet> {
170 diagnostics.set_max_to_print(max_to_print);
171 let warnings = diagnostics.split_off_warnings();
172 if let Some(warnings) = warnings {
173 if print_warnings {
174 let _ = writeln!(std::io::stderr(), "{}", warnings.display());
176 }
177 }
178
179 if diagnostics.is_empty() {
180 Ok(())
181 } else {
182 Err(diagnostics)
183 }
184}