1#![allow(clippy::ref_option)]
2#![allow(clippy::case_sensitive_file_extension_comparisons)]
3#![allow(clippy::cast_possible_truncation)]
4#![allow(unused_variables)]
5#![allow(clippy::needless_pass_by_value)]
6
7use crate::{
8 quickparse::{
9 latex::{
10 Environment, KeyValKind, LaTeXParser, Macro, ParsedKeyValue,
11 rules::{
12 AnyMacro, DynMacro, EnvironmentResult, EnvironmentRule, MacroResult, MacroRule,
13 },
14 },
15 stex::structs::MorphismKind,
16 tokenizer::TeXTokenizer,
17 },
18 tex,
19};
20use flams_math_archives::{
21 MathArchive,
22 backend::{GlobalBackend, LocalBackend},
23};
24use flams_utils::parsing::SourceParser;
25use flams_utils::{
26 CondSerialize, impossible,
27 sourcerefs::{LSPLineCol, StringPosition, StringRange},
28 vecmap::VecMap,
29};
30use ftml_ontology::narrative::elements::paragraphs::ParagraphKind;
31use ftml_uris::{
32 ArchiveId, DocumentUri, IsNarrativeUri, Language, ModuleUri, SymbolUri, UriName,
33 UriWithArchive, UriWithPath,
34};
35use smallvec::SmallVec;
36use std::{borrow::Cow, path::Path};
37
38use super::{
39 DiagnosticLevel,
40 structs::{
41 GroupKind, InlineMorphAssKind, InlineMorphAssign, MacroArg, ModuleOrStruct,
42 ModuleReference, ModuleRule, ModuleRules, MorphismSpec, STeXGroup, STeXModuleStore,
43 STeXParseState, STeXToken, SymbolReference, SymbolRule,
44 },
45};
46
47#[must_use]
48#[allow(clippy::type_complexity)]
49pub fn all_rules<'a, MS: STeXModuleStore>() -> [(
50 &'static str,
51 MacroRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
52); 47] {
53 [
54 ("importmodule", importmodule as _),
55 ("setmetatheory", setmetatheory as _),
56 ("usemodule", usemodule as _),
57 ("requiremodule", usemodule as _),
58 ("usestructure", usestructure as _),
59 ("inputref", inputref as _),
60 ("includeproblem", includeproblem as _),
61 ("mhinput", mhinput as _),
62 ("mhgraphics", mhgraphics as _),
63 ("cmhgraphics", mhgraphics as _),
64 ("stexstyleassertion", stexstyleassertion as _),
65 ("stexstyledefinition", stexstyledefinition as _),
66 ("stexstyleparagraph", stexstyleparagraph as _),
67 ("symdecl", symdecl as _),
68 ("textsymdecl", textsymdecl as _),
69 ("symdef", symdef as _),
70 ("vardef", vardef as _),
71 ("newvar", newvar as _),
72 ("varseq", varseq as _),
73 ("newseq", newseq as _),
74 ("symref", symref as _),
75 ("sr", symref as _),
76 ("symname", symname as _),
77 ("sn", symname as _),
78 ("Symname", Symname as _),
79 ("Sn", Symname as _),
80 ("sns", symnames as _),
81 ("Sns", Symnames as _),
82 ("symuse", symuse as _),
83 ("svar", svar as _),
84 ("notation", notation as _),
85 ("definame", defi_only as _),
86 ("Definame", defi_only as _),
87 ("definames", defi_only as _),
88 ("Definames", defi_only as _),
89 ("definiendum", defi_only as _),
90 ("definiens", defi_only as _),
91 ("defnotation", defi_only as _),
92 ("inlinedef", inlinedef as _),
93 ("inlineass", inlineass as _),
94 ("inlinepara", inlinepara as _),
95 ("inlineex", inlineex as _),
96 ("copymod", copymod as _),
97 ("interpretmod", interpretmod as _),
98 ("precondition", precondition as _),
99 ("objective", objective as _),
100 ("sref", sref as _),
101 ]
102}
103
104#[must_use]
105#[allow(clippy::type_complexity)]
106pub fn declarative_rules<'a, MS: STeXModuleStore>() -> [(
107 &'static str,
108 MacroRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
109); 14] {
110 [
111 ("importmodule", importmodule as _),
112 ("setmetatheory", setmetatheory as _),
113 ("stexstyleassertion", stexstyleassertion as _),
114 ("stexstyledefinition", stexstyledefinition as _),
115 ("stexstyleparagraph", stexstyleparagraph as _),
116 ("symdecl", symdecl as _),
117 ("textsymdecl", textsymdecl as _),
118 ("symdef", symdef as _),
119 ("inlinedef", inlinedef as _),
120 ("inlineass", inlineass as _),
121 ("inlinepara", inlinepara as _),
122 ("inlineex", inlineex as _),
123 ("copymod", copymod as _),
124 ("interpretmod", interpretmod as _),
125 ]
126}
127
128#[must_use]
129#[allow(clippy::type_complexity)]
130pub fn all_env_rules<'a, MS: STeXModuleStore>() -> [(
131 &'static str,
132 EnvironmentRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
133); 16] {
134 [
135 ("smodule", (smodule_open as _, smodule_close as _)),
136 (
137 "mathstructure",
138 (mathstructure_open as _, mathstructure_close as _),
139 ),
140 (
141 "extstructure",
142 (extstructure_open as _, extstructure_close as _),
143 ),
144 (
145 "extstructure*",
146 (extstructure_ast_open as _, extstructure_ast_close as _),
147 ),
148 ("sassertion", (sassertion_open as _, sassertion_close as _)),
149 (
150 "sdefinition",
151 (sdefinition_open as _, sdefinition_close as _),
152 ),
153 ("sparagraph", (sparagraph_open as _, sparagraph_close as _)),
154 ("sexample", (sexample_open as _, sexample_close as _)),
155 (
156 "ndefinition",
157 (sdefinition_open as _, sdefinition_close as _),
158 ),
159 ("nparagraph", (sparagraph_open as _, sparagraph_close as _)),
160 ("copymodule", (copymodule_open as _, copymodule_close as _)),
161 (
162 "copymodule*",
163 (copymodule_ast_open as _, copymodule_ast_close as _),
164 ),
165 (
166 "interpretmodule",
167 (interpretmodule_open as _, interpretmodule_close as _),
168 ),
169 (
170 "interpretmodule*",
171 (
172 interpretmodule_ast_open as _,
173 interpretmodule_ast_close as _,
174 ),
175 ),
176 ("sproblem", (sproblem_open as _, sproblem_close as _)),
177 ("subproblem", (subproblem_open as _, subproblem_close as _)),
178 ]
179}
180
181#[must_use]
182#[allow(clippy::type_complexity)]
183pub fn declarative_env_rules<'a, MS: STeXModuleStore>() -> [(
184 &'static str,
185 EnvironmentRule<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
186); 12] {
187 [
188 ("smodule", (smodule_open as _, smodule_close as _)),
189 (
190 "mathstructure",
191 (mathstructure_open as _, mathstructure_close as _),
192 ),
193 (
194 "extstructure",
195 (extstructure_open as _, extstructure_close as _),
196 ),
197 (
198 "extstructure*",
199 (extstructure_ast_open as _, extstructure_ast_close as _),
200 ),
201 ("sassertion", (sassertion_open as _, sassertion_close as _)),
202 (
203 "sdefinition",
204 (sdefinition_open as _, sdefinition_close as _),
205 ),
206 ("sparagraph", (sparagraph_open as _, sparagraph_close as _)),
207 ("sexample", (sexample_open as _, sexample_close as _)),
208 ("copymodule", (copymodule_open as _, copymodule_close as _)),
209 (
210 "copymodule*",
211 (copymodule_ast_open as _, copymodule_ast_close as _),
212 ),
213 (
214 "interpretmodule",
215 (interpretmodule_open as _, interpretmodule_close as _),
216 ),
217 (
218 "interpretmodule*",
219 (
220 interpretmodule_ast_open as _,
221 interpretmodule_ast_close as _,
222 ),
223 ),
224 ]
225}
226
227macro_rules! stex {
228 ($p:ident => @begin $($stuff:tt)+) => {
229 tex!(<{'a,Pos:StringPosition,MS:STeXModuleStore} E{'a,Pos,STeXToken<Pos>} P{'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>} R{'a,Pos,STeXToken<Pos>}>
230 $p => @begin $($stuff)*
231 );
232 };
233 ($p:ident => $($stuff:tt)+) => {
234 tex!(<{'a,Pos:StringPosition,MS:STeXModuleStore} M{'a,Pos} P{'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>} R{'a,Pos,STeXToken<Pos>}>
235 $p => $($stuff)*
236 );
237 };
238 (LSP: $p:ident => @begin $($stuff:tt)+) => {
239 tex!(<{'a,MS:STeXModuleStore} E{'a,LSPLineCol,STeXToken<LSPLineCol>} P{'a,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>} R{'a,LSPLineCol,STeXToken<LSPLineCol>}>
240 $p => @begin $($stuff)*
241 );
242 };
243 (LSP: $p:ident => $($stuff:tt)+) => {
244 tex!(<{'a,MS:STeXModuleStore} M{'a,LSPLineCol} P{'a,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>} R{'a,LSPLineCol,STeXToken<LSPLineCol>}>
245 $p => $($stuff)*
246 );
247 };
248}
249
250fn parse_id<'a, P: StringPosition>(
251 id: &str,
252 pos: P,
253 tkn: &mut TeXTokenizer<'a, P>,
254) -> Option<ArchiveId> {
255 match ArchiveId::new(id) {
256 Ok(id) => Some(id),
257 Err(e) => {
258 tkn.problem(
259 pos,
260 format_args!("Invalid Archive Id {id}: {e}"),
261 DiagnosticLevel::Error,
262 );
263 None
264 }
265 }
266}
267
268stex!(LSP: p => importmodule[archive:str]{module:name} => {
269 let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
270 parse_id(a,importmodule.range.start,&mut p.tokenizer),
271 Some(r)
272 ));
273 if let Some(r) = p.state.resolve_module(module.0, archive) {
274 let path = p.state.in_path.as_ref().expect("this is a bug");
275 let (state,groups) = p.split();
276 state.add_import(&r, groups,importmodule.range);
277 MacroResult::Success(STeXToken::ImportModule {
278 archive_range, path_range:module.1,module:r,
279 full_range:importmodule.range, token_range:importmodule.token_range
280 })
281 } else {
282 p.tokenizer.problem(importmodule.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
283 MacroResult::Simple(importmodule)
284 }
285});
286
287stex!(p => importmodule_deps[archive:str]{module:name} => {
288 let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
289 parse_id(a,importmodule_deps.range.start,&mut p.tokenizer),
290 Some(r)
291 ));
292
293 if let Some(r) = p.state.resolve_module(module.0, archive) {
294 MacroResult::Success(STeXToken::ImportModule {
295 archive_range, path_range:module.1,module:r,
296 full_range:importmodule_deps.range, token_range:importmodule_deps.token_range
297 })
298 } else {
299 p.tokenizer.problem(importmodule_deps.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
300 MacroResult::Simple(importmodule_deps)
301 }
302});
303
304stex!(LSP:p => usemodule[archive:str]{module:name} => {
305 let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
306 parse_id(a,usemodule.range.start,&mut p.tokenizer),
307 Some(r)
308 ));
309 if let Some(r) = p.state.resolve_module(module.0, archive) {
310 let (state,groups) = p.split();
311 state.add_use(&r, groups,usemodule.range);
312 MacroResult::Success(STeXToken::UseModule {
313 archive_range, path_range:module.1,module:r,
314 full_range:usemodule.range, token_range:usemodule.token_range
315 })
316 } else {
317 p.tokenizer.problem(usemodule.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
318 MacroResult::Simple(usemodule)
319 }
320 }
321);
322
323stex!(LSP:p => usestructure{exts:!name} => {
324 let (state,mut groups) = p.split();
325 let Some((sym,rules)) = state.get_structure(&groups,&exts.0) else {
326 groups.tokenizer.problem(exts.1.start, format!("Unknown structure {}",exts.0),DiagnosticLevel::Error);
327 return MacroResult::Simple(usestructure)
328 };
329 state.use_structure(&sym,&rules,&mut groups,usestructure.range);
330 MacroResult::Success(STeXToken::UseStructure {
331 structure:sym,structure_range:exts.1,
332 full_range:usestructure.range, token_range:usestructure.token_range
333 })
334}
335);
336
337stex!(p => usemodule_deps[archive:str]{module:name} => {
338 let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
339 parse_id(a,usemodule_deps.range.start,&mut p.tokenizer),
340 Some(r)
341 ));
342 if let Some(r) = p.state.resolve_module(module.0, archive) {
343 MacroResult::Success(STeXToken::UseModule {
344 archive_range, path_range:module.1,module:r,
345 full_range:usemodule_deps.range,token_range:usemodule_deps.token_range
346 })
347 } else {
348 p.tokenizer.problem(usemodule_deps.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
349 MacroResult::Simple(usemodule_deps)
350 }
351 }
352);
353
354stex!(p => setmetatheory[archive:str]{module:name} => {
355 let (archive,archive_range) = archive.map_or((None,None),|(a,r)| (
356 parse_id(a,setmetatheory.range.start,&mut p.tokenizer),
357 Some(r)
358 ));
359 if let Some(r) = p.state.resolve_module(module.0, archive) {
360 MacroResult::Success(STeXToken::SetMetatheory {
361 archive_range, path_range:module.1,module:r,
362 full_range:setmetatheory.range, token_range:setmetatheory.token_range
363 })
364 } else {
365 p.tokenizer.problem(setmetatheory.range.start, format!("Module {} not found",module.0),DiagnosticLevel::Error);
366 MacroResult::Simple(setmetatheory)
367 }
368 }
369);
370
371stex!(p => stexstyleassertion[_]{_}{_}!);
372stex!(p => stexstyledefinition[_]{_}{_}!);
373stex!(p => stexstyleparagraph[_]{_}{_}!);
374
375stex!(p => inputref('*'?_s)[archive:str]{filepath:name} => {
376 let archive = archive.and_then(|(a,r)|
377 parse_id(a,inputref.range.start,&mut p.tokenizer).map(|a| (a,r))
378 );
379 let rel_path: std::sync::Arc<str> = if filepath.0.ends_with(".tex") {
380 filepath.0.into()
381 } else {
382 format!("{}.tex",filepath.0).into()
383 };
384 {
385 if let Some(id) = archive.as_ref().map_or_else(||
386 p.state.archive.as_ref().map(|a| a.archive_id()),
387 |(a,_)| Some(a)
388 ) {
389 p.state.backend.with_local_archive(id,|a|
390 if let Some(a) = a {
391 let path = a.source_dir();
392 let path = rel_path.as_ref().split('/').fold(path,|p,s| p.join(s));
393 if !path.exists() {
394 p.tokenizer.problem(filepath.1.start,format!("File {} not found",path.display()),DiagnosticLevel::Error);
395 }
396 }
397 );
398 }
399 }
400 let filepath = (rel_path,filepath.1);
401 MacroResult::Success(STeXToken::Inputref {
402 archive, filepath,full_range:inputref.range,
403 token_range:inputref.token_range
404 })
405 }
406);
407
408stex!(p => mhinput[archive:str]{filepath:name} => {
409 let archive = archive.and_then(|(a,r)|
410 parse_id(a,mhinput.range.start,&mut p.tokenizer).map(|a| (a,r))
411 );
412 let rel_path: std::sync::Arc<str> = if filepath.0.ends_with(".tex") {
413 filepath.0.into()
414 } else {
415 format!("{}.tex",filepath.0).into()
416 };
417 {
418 if let Some(id) = archive.as_ref().map_or_else(||
419 p.state.archive.as_ref().map(|a| a.archive_id()),
420 |(a,_)| Some(a)
421 ) {
422 p.state.backend.with_local_archive(id,|a|
423 if let Some(a) = a {
424 let path = a.source_dir();
425 let path = rel_path.as_ref().split('/').fold(path,|p,s| p.join(s));
426 if !path.exists() {
427 p.tokenizer.problem(filepath.1.start,format!("File {} not found",path.display()),DiagnosticLevel::Error);
428 }
429 }
430 );
431 }
432 }
433 let filepath = (rel_path,filepath.1);
434 MacroResult::Success(STeXToken::MHInput {
435 archive, filepath,full_range:mhinput.range,
436 token_range:mhinput.token_range
437 })
438 }
439);
440
441fn strip_comments(s: &str) -> Cow<'_, str> {
442 s.find('%').map_or(Cow::Borrowed(s), |i| {
443 let rest = &s[i..];
444 rest.find("\r\n")
445 .or_else(|| rest.find('\n'))
446 .or_else(|| rest.find('\r'))
447 .map_or_else(
448 || Cow::Borrowed(&s[..i]),
449 |j| {
450 let r = strip_comments(&rest[j..]);
451 if r.is_empty() {
452 Cow::Borrowed(&s[..i])
453 } else {
454 Cow::Owned(format!("{}{}", &s[..i], r))
455 }
456 },
457 )
458 })
459}
460
461macro_rules! optargtype {
462 ($parser:ident => $name:ident { $( {$fieldname:ident = $id:literal : $($tp:tt)+} )* $(_ = $default:ident)? }) => {
463 #[derive(serde::Serialize)]
464 pub enum $name<Pos:StringPosition> {
465 $(
466 $fieldname(ParsedKeyValue<Pos,optargtype!(@TYPE $($tp)*)>)
467 ),*
468 $(, $default(StringRange<Pos>,Box<str>))?
469 }
470 impl<Pos:StringPosition> std::fmt::Debug for $name<Pos> {
471 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472 f.write_str(stringify!($name))
473 }
474 }
475 impl<Pos:StringPosition> Clone for $name<Pos> {
476 fn clone(&self) -> Self {
477 match self {
478 $(
479 Self::$fieldname(v) => Self::$fieldname(v.clone())
480 ),*
481 }
482 }
483 }
484 impl<'a,Pos:StringPosition,MS:STeXModuleStore>
485 KeyValKind<'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>> for $name<Pos> {
486 fn next_val(
487 $parser:&mut crate::quickparse::latex::KeyValParser<'a, '_,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>>,
488 key:&str
489 ) -> Option<Self> {
490 #[allow(unused_imports)]
491 use super::super::latex::KeyValParsable;
492 match key {
493 $(
494 $id => optargtype!(@PARSE $parser $fieldname $($tp)*),
495 )*
496 _ => optargtype!(@DEFAULT $($parser $default)?)
497 }
498 }
499 }
500 };
501 ($parser:ident => $name:ident <T> { $( {$fieldname:ident = $id:literal : $($tp:tt)+} )* $(_ = $default:ident)? } @ $iter:ident) => {
502 #[derive(serde::Serialize)]
503 pub enum $name<Pos:StringPosition,T:CondSerialize> {
504 $(
505 $fieldname(ParsedKeyValue<Pos,optargtype!(@TYPE T $($tp)*)>)
506 ),*
507 $(, $default(StringRange<Pos>,Box<str>))?
508 }
509 impl<Pos:StringPosition,T:CondSerialize> std::fmt::Debug for $name<Pos,T> {
510 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511 f.write_str(stringify!($name))
512 }
513 }
514 impl<Pos:StringPosition,T:Clone+CondSerialize> Clone for $name<Pos,T> {
515 fn clone(&self) -> Self {
516 match self {
517 $(
518 Self::$fieldname(v) => Self::$fieldname(v.clone())
519 ),*
520 $(,
521 Self::$default(r,s) => Self::$default(*r,s.clone())
522 )?
523 }
524 }
525 }
526
527 impl<'a,Pos:StringPosition,MS:STeXModuleStore>
528 KeyValKind<'a,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>> for $name<Pos,STeXToken<Pos>> {
529 fn next_val(
530 $parser:&mut crate::quickparse::latex::KeyValParser<'a, '_,Pos,STeXToken<Pos>,STeXParseState<'a,Pos,MS>>,
531 key:&str
532 ) -> Option<Self> {
533 #[allow(unused_imports)]
534 use super::super::latex::KeyValParsable;
535 match key {
536 $(
537 $id => optargtype!(@PARSE+ $parser $fieldname $($tp)*),
538 )*
539 _ => optargtype!(@DEFAULT $($parser $default)?)
540 }
541 }
542 }
543
544 impl<Pos:StringPosition,T1:CondSerialize> $name<Pos,T1> {
545 pub fn into_other<T2:CondSerialize>(self,mut cont:impl FnMut(Vec<T1>) -> Vec<T2>) -> $name<Pos,T2> {
546 match self {
547 $(
548 $name::$fieldname(val) => optargtype!(@TRANSLATE val cont $name $fieldname $($tp)*)
549 ),*
550 $(, $name::$default(range,name) => $name::$default(range,name))?
551 }
552 }
553 }
554
555 pub struct $iter<'a,Pos:StringPosition,T:CondSerialize>{
556 current:Option<std::slice::Iter<'a,T>>,
557 nexts:std::slice::Iter<'a,$name<Pos,T>>
558 }
559 impl<'a,Pos:StringPosition,T:CondSerialize> $iter<'a,Pos,T> {
560 pub fn new(sn:&'a[$name<Pos,T>]) -> Self {
561 Self { current:None,nexts:sn.iter()}
562 }
563 }
564 impl<'a,Pos:StringPosition,T:CondSerialize> Iterator for $iter<'a,Pos,T> {
565 type Item = &'a T;
566 fn next(&mut self) -> Option<Self::Item> {
567 if let Some(c) = &mut self.current {
568 if let Some(n) = c.next() { return Some(n)}
569 }
570 loop {
571 let Some(n) = self.nexts.next() else {return None};
572 match n {
573 optargtype!(@DOITER e $name {} {$($fieldname $($tp)*; )*}) => {
574 let mut next = e.val.iter();
575 if let Some(n) = next.next() {
576 self.current = Some(next);
577 return Some(n)
578 }
579 }
580 _ => ()
581 }
582 }
583 }
584 }
585 };
586 (LSP $parser:ident => $name:ident <T> { $( {$fieldname:ident = $id:literal : $($tp:tt)+} )* $(_ = $default:ident)? } @ $iter:ident) => {
587
588 #[derive(serde::Serialize)]
589 pub enum $name<Pos:StringPosition,T:CondSerialize> {
590 $(
591 $fieldname(ParsedKeyValue<Pos,optargtype!(@TYPE T $($tp)*)>)
592 ),*
593 $(, $default(StringRange<Pos>,Box<str>))?
594 }
595 impl<Pos:StringPosition,T:CondSerialize> std::fmt::Debug for $name<Pos,T> {
596 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
597 f.write_str(stringify!($name))
598 }
599 }
600 impl<Pos:StringPosition,T:Clone+CondSerialize> Clone for $name<Pos,T> {
601 fn clone(&self) -> Self {
602 match self {
603 $(
604 Self::$fieldname(v) => Self::$fieldname(v.clone())
605 ),*
606 $(,
607 Self::$default(r,s) => Self::$default(*r,s.clone())
608 )?
609 }
610 }
611 }
612
613 impl<'a,MS:STeXModuleStore>
614 KeyValKind<'a,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>> for $name<LSPLineCol,STeXToken<LSPLineCol>> {
615 fn next_val(
616 $parser:&mut crate::quickparse::latex::KeyValParser<'a, '_,LSPLineCol,STeXToken<LSPLineCol>,STeXParseState<'a,LSPLineCol,MS>>,
617 key:&str
618 ) -> Option<Self> {
619 #[allow(unused_imports)]
620 use super::super::latex::KeyValParsable;
621 match key {
622 $(
623 $id => optargtype!(@PARSE+ $parser $fieldname $($tp)*),
624 )*
625 _ => optargtype!(@DEFAULT $($parser $default)?)
626 }
627 }
628 }
629
630 impl<T1:CondSerialize> $name<LSPLineCol,T1> {
631 pub fn into_other<T2:CondSerialize>(self,mut cont:impl FnMut(Vec<T1>) -> Vec<T2>) -> $name<LSPLineCol,T2> {
632 match self {
633 $(
634 $name::$fieldname(val) => optargtype!(@TRANSLATE val cont $name $fieldname $($tp)*)
635 ),*
636 $(, $name::$default(range,name) => $name::$default(range,name))?
637 }
638 }
639 }
640
641 pub struct $iter<'a,T:CondSerialize>{
642 current:Option<std::slice::Iter<'a,T>>,
643 nexts:std::slice::Iter<'a,$name<LSPLineCol,T>>
644 }
645 impl<'a,T:CondSerialize> $iter<'a,T> {
646 pub fn new(sn:&'a[$name<LSPLineCol,T>]) -> Self {
647 Self { current:None,nexts:sn.iter()}
648 }
649 }
650 impl<'a,T:CondSerialize> Iterator for $iter<'a,T> {
651 type Item = &'a T;
652 fn next(&mut self) -> Option<Self::Item> {
653 if let Some(c) = &mut self.current {
654 if let Some(n) = c.next() { return Some(n)}
655 }
656 loop {
657 let Some(n) = self.nexts.next() else {return None};
658 match n {
659 optargtype!(@DOITER e $name {} {$($fieldname $($tp)*; )*}) => {
660 let mut next = e.val.iter();
661 if let Some(n) = next.next() {
662 self.current = Some(next);
663 return Some(n)
664 }
665 }
666 _ => ()
667 }
668 }
669 }
670 }
671 };
672 (@DEFAULT ) => { None };
673 (@DEFAULT $parser:ident $default:ident) => {
674 if $parser.has_value {
675 $parser.skip_value();
676 $parser.problem("Invalid value",DiagnosticLevel::Error);
677 None
678 } else {
679 Some(Self::$default($parser.key_range,$parser.key.to_string().into()))
680 }
681 };
682
683 (@DOITER $e:ident $name:ident {$($tks:tt)*} {} ) => {$($tks)*};
684
685 (@TYPE $(T)? str) => {Box<str>};
686 (@PARSE $(+)? $parser:ident $fieldname:ident str ) => {$parser.parse().map(Self::$fieldname)};
687 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident str) => {
688 $name::$fieldname($val)
689 };
690 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident str; $($rest:tt)* }) => {
691 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
692 };
693
694 (@TYPE $(T)? ()) => {()};
695 (@PARSE $(+)? $parser:ident $fieldname:ident () ) => {$parser.parse().map(Self::$fieldname)};
696 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident ()) => {
697 $name::$fieldname($val)
698 };
699 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident (); $($rest:tt)* }) => {
700 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
701 };
702
703 (@TYPE $(T)? Language) => {Language};
704 (@PARSE $(+)? $parser:ident $fieldname:ident Language ) => {$parser.parse().map(Self::$fieldname)};
705 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident Language) => {
706 $name::$fieldname($val)
707 };
708 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident Language; $($rest:tt)* }) => {
709 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
710 };
711
712 (@TYPE $(T)? f32) => {f32};
713 (@PARSE $(+)? $parser:ident $fieldname:ident f32 ) => {$parser.parse().map(Self::$fieldname)};
714 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident f32) => {
715 $name::$fieldname($val)
716 };
717 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident f32; $($rest:tt)* }) => {
718 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
719 };
720
721 (@TYPE $(T)? bool?) => {bool};
722 (@PARSE $(+)? $parser:ident $fieldname:ident bool? ) => {
723 if $parser.has_value {$parser.parse().map(Self::$fieldname)} else { Some(Self::$fieldname(
724 ParsedKeyValue{key_range:$parser.key_range,val_range:StringRange{start:$parser.start,end:$parser.start},val:true}
725 )) }
726 };
727 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident bool?) => {
728 $name::$fieldname($val)
729 };
730 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident bool?; $($rest:tt)* }) => {
731 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
732 };
733
734 (@TYPE $(T)? !) => {()};
735 (@PARSE $(+)? $parser:ident $fieldname:ident ! ) => {{
736 if $parser.has_value {
737 $parser.problem("Invalid value",DiagnosticLevel::Error);
738 }
739 $parser.parse().map(Self::$fieldname)
740 }};
741 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident !) => {
742 $name::$fieldname($val)
743 };
744 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident !; $($rest:tt)* }) => {
745 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
746 };
747
748 (@TYPE T T*) => {Vec<T>};
749 (@PARSE+ $parser:ident $fieldname:ident T* ) => {$parser.parse().map(Self::$fieldname)};
750 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident T*) => {
751 $name::$fieldname(ParsedKeyValue{key_range:$val.key_range,val_range:$val.val_range,val:$cont($val.val)})
752 };
753 (@DOITER $e:ident $name:ident {} {$fieldname:ident T*; $($rest:tt)* }) => {
754 optargtype!(@DOITER $e $name {$name::$fieldname($e)} { $($rest)* })
755 };
756 (@DOITER $e:ident $name:ident {$($tks:tt)+} {$fieldname:ident T*; $($rest:tt)* }) => {
757 optargtype!(@DOITER $e $name {$($tks)* | $name::$fieldname($e)} { $($rest)* })
758 };
759
760 (@TYPE $(T)? Args) => {u8};
761 (@PARSE $(+)? $parser:ident $fieldname:ident Args) => {{
762 let Some(s) = $parser.read_value_str_normalized() else {
763 $parser.problem("Missing value for args",DiagnosticLevel::Error);
764 return None
765 };
766 if s.bytes().all(|b| b.is_ascii_digit()) && s.len() == 1 {
767 let arg:u8 = s.parse().unwrap_or_else(|_| unreachable!());
768 Some(Self::Args($parser.to_key_value(arg)))
769 } else if s.bytes().all(|b| b == b'i' || b == b'a' || b == b'b' || b == b'B') {
770 if s.len() > 9 {
771 $parser.problem("Too many arguments",DiagnosticLevel::Error);
772 None
773 } else {
774 Some(Self::Args($parser.to_key_value(s.len() as u8)))
775 }
776 } else {
777 $parser.problem(format!("Invalid args value: >{s}<"),DiagnosticLevel::Error);
778 None
779 }
780 }};
781 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident Args) => {
782 $name::$fieldname($val)
783 };
784 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident Args; $($rest:tt)* }) => {
785 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
786 };
787
788 (@TYPE $(T)? { $tp:ty => $($r:tt)*}) => {$tp};
789 (@PARSE $(+)? $parser:ident $fieldname:ident { $tp:ty => $($r:tt)*}) => {{$($r)*}};
790 (@TRANSLATE $val:ident $cont:ident $name:ident $fieldname:ident { $tp:ty => $($r:tt)*}) => {
791 $name::$fieldname($val)
792 };
793 (@DOITER $e:ident $name:ident {$($tks:tt)*} {$fieldname:ident { $tp:ty => $($r:tt)*}; $($rest:tt)* }) => {
794 optargtype!(@DOITER $e $name {$($tks)*} { $($rest)* })
795 };
796}
797
798optargtype! {parser =>
799 SRefOptsA<T> {
800 {Archive = "archive": str}
801 {File = "file": str}
802 {Fallback = "fallback": T*}
803 {Pre = "pre": ()}
804 {Post = "post": ()}
805 } @ SRefOptsAIter
806}
807optargtype! {parser =>
808 SRefOptsB<T> {
809 {Archive = "archive": str}
810 {File = "file": str}
811 {Title = "title": T*}
812 } @ SRefOptsBIter
813}
814
815stex!(p => sref[args_a:type SRefOptsA<Pos, STeXToken<Pos>>]{label:name}[args_b:type SRefOptsB<Pos, STeXToken<Pos>>] => {
816 let args_a = args_a.unwrap_or_default();
817 let args_b = args_b.unwrap_or_default();
818 let archive = args_a.iter().find_map(|p| if let SRefOptsA::Archive(a) = p {Some(a)} else {None})
819 .and_then(|pair|
820 parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer)
821 );
822 let rel_path: Option<&str> = args_a.iter().find_map(|p|
823 if let SRefOptsA::File(f) = p {Some(&*f.val)} else {None}
824 );
825 let in_archive = args_b.iter().find_map(|p| if let SRefOptsB::Archive(a) = p {Some(a)} else {None})
826 .and_then(|pair|
827 parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer)
828 );
829 let in_rel_path: Option<&str> = args_b.iter().find_map(|p|
830 if let SRefOptsB::File(f) = p {Some(&*f.val)} else {None}
831 );
832
833 let (doc_uri,target_path):(DocumentUri,std::sync::Arc<Path>) = if let Some(rp) = rel_path {
834 if let Some(uri) = parse_doc_ref(p,archive.as_ref(),&rp,sref.token_range.end) {
835 uri
836 } else {
837 return MacroResult::Simple(sref);
838 }
839 } else if let Some(rp) = &p.state.in_path{
840 (p.state.doc_uri.clone(),rp.clone())
841 } else {
842 p.tokenizer
843 .problem(sref.range.start, "file not found", DiagnosticLevel::Error);
844 return MacroResult::Simple(sref);
845 };
846 let target_uri = doc_uri & {
847 if let Ok(l) = label.0.parse::<UriName>() {
848 l
849 } else {
850 p.tokenizer.problem(sref.range.start, format_args!("invalid label name {}",label.0), DiagnosticLevel::Error);
851 return MacroResult::Simple(sref);
852 }
853 };
854 let in_doc_uri = if let Some(rp) = &in_rel_path {
855 if let Some(uri) = parse_doc_ref(p,in_archive.as_ref(),rp,label.1.end) {
856 Some(uri)
857 } else {
858 return MacroResult::Simple(sref);
859 }
860 } else {None};
861 MacroResult::Success(STeXToken::SRef {
862 full_range: sref.range,
863 token_range: sref.token_range,
864 opt_args: args_a,
865 label_range: label.1,
866 target_path,
867 in_opt_args: args_b,
868 target: target_uri,
869 in_doc: in_doc_uri
870 })
871});
872
873fn parse_doc_ref<'a, Pos: StringPosition, MS: STeXModuleStore>(
874 p: &mut crate::quickparse::latex::LaTeXParser<
875 'a,
876 Pos,
877 STeXToken<Pos>,
878 STeXParseState<'a, Pos, MS>,
879 >,
880 archive: Option<&ArchiveId>,
881 relpath: &str,
882 errpos: Pos,
883) -> Option<(DocumentUri, std::sync::Arc<Path>)> {
884 let (archive_uri, mut path) = if let Some(a) = archive {
885 if let Some(uri) = p.state.backend.with_local_archive(a, |a| {
886 a.map(|a| (a.uri().clone(), a.source_dir().join(relpath)))
887 }) {
888 uri
889 } else {
890 p.tokenizer.problem(
891 errpos,
892 format_args!("Unknown archive {a}"),
893 DiagnosticLevel::Error,
894 );
895 return None;
896 }
897 } else if let Some(a) = p.state.archive
898 && let Some(pth) = &p.state.in_path
899 {
900 (a.clone(), {
901 let mut np = &**pth;
902 while !np.ends_with("source") {
903 let Some(par) = np.parent() else {
904 p.tokenizer
905 .problem(errpos, "file not found", DiagnosticLevel::Error);
906 return None;
907 };
908 np = par;
909 }
910 np.join(relpath)
911 })
912 } else {
913 p.tokenizer
914 .problem(errpos, "archive missing", DiagnosticLevel::Error);
915 return None;
916 };
917 path.add_extension("tex");
918 if let Ok(u) = DocumentUri::from_archive_relpath(archive_uri, &format!("{relpath}.tex")) {
919 Some((u, path.into()))
920 } else {
921 p.tokenizer.problem(
922 errpos,
923 format_args!("invalid document path {relpath}"),
924 DiagnosticLevel::Error,
925 );
926 None
927 }
928}
929
930optargtype! {parser =>
931 IncludeProblemArg {
932 {Pts = "pts" : f32}
933 {Min = "min": f32}
934 {Archive = "archive": str}
935 }
936}
937
938stex!(p => includeproblem[args:type IncludeProblemArg<Pos>]{filepath:name} => {
939 let args = args.unwrap_or_default();
940 let archive = args.iter().find_map(|p| if let IncludeProblemArg::Archive(a) = p {Some(a)} else {None})
941 .and_then(|pair|
942 parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer).map(|a| (a,pair.val_range))
943 );
944 let rel_path: std::sync::Arc<str> = if filepath.0.ends_with(".tex") {
945 filepath.0.into()
946 } else {
947 format!("{}.tex",filepath.0).into()
948 };
949 {
950 if let Some(id) = archive.as_ref().map_or_else(||
951 p.state.archive.as_ref().map(|a| a.archive_id()),
952 |(a,_)| Some(a)
953 ) {
954 p.state.backend.with_local_archive(id,|a|
955 if let Some(a) = a {
956 let path = a.source_dir();
957 let path = rel_path.as_ref().split('/').fold(path,|p,s| p.join(s));
958 if !path.exists() {
959 p.tokenizer.problem(filepath.1.start,format!("File {} not found",path.display()),DiagnosticLevel::Error);
960 }
961 }
962 );
963 }
964 }
965 let filepath = (rel_path,filepath.1);
966 MacroResult::Success(STeXToken::IncludeProblem {
967 filepath,full_range:includeproblem.range,archive,
968 token_range:includeproblem.token_range,args
969 })
970 }
971);
972
973optargtype! {parser =>
974 MHGraphicsArg {
975 {Width = "width" : str}
976 {Height = "height": str}
977 {Archive = "archive": str}
978 {Viewport = "viewport": str}
979 {Trim = "trim": str}
980 {Scale = "scale": f32}
981 {Angle = "angle": f32}
982 {Clip = "clip":()}
983 {KeepAspectRatio = "keepaspectratio":()}
984 }
985}
986
987stex!(p => mhgraphics[args:type MHGraphicsArg<Pos>]{filepath:name} => {
988 fn img_exists(path:&Path,rel_path:&mut String,warn:impl FnOnce(&str)) -> bool {
989 const IMG_EXTS: [&str;10] = ["png","PNG","jpg","JPG","jpeg","JPEG","bmp","BMP","pdf","PDF"];
990 if let Some(e) = path.extension().and_then(|s| s.to_str().and_then(|s| IMG_EXTS.iter().find(|e| **e == s))) {
991 if ["pdf","PDF"].contains(e) {
992 warn(".pdf extension not suitable for HTML\n\nrustex will substitute with a png instead.\nYou may want to directly use the .png here");
993 }
994 return path.exists();
995 }
996 for e in &IMG_EXTS {
997 if path.with_extension(e).exists() {
998 if ["pdf","PDF"].contains(e) {
999 warn(".pdf extension not suitable for HTML\n\nrustex will substitute with a png instead.\nYou may want to directly use the .png here");
1000 }
1001 if let Some(ex) = path.extension().and_then(|s| s.to_str()) {
1002 let len = rel_path.len() - ex.len();
1003 rel_path.truncate(len);
1004 } else {
1005 rel_path.push('.');
1006 }
1007 rel_path.push_str(*e);
1008 return true
1009 }
1010 }
1011 false
1012 }
1013 let args = args.unwrap_or_default();
1014 for a in &args {
1015 match a {
1016 MHGraphicsArg::Scale(x) => p.tokenizer.problem(x.key_range.start,"`scale` results in an image size relative to the original image file. Absolute values (`width` or `height`) are strongly encouraged",DiagnosticLevel::Warning),
1017 _ => ()
1018 }
1019 }
1020 if !args.iter().any(|e| matches!(e,MHGraphicsArg::Width(_)|MHGraphicsArg::Height(_))) {
1021 p.tokenizer.problem(mhgraphics.token_range.start,"No `width` or `height` attribute in image. It is strongly encouraged to provide one of them.",DiagnosticLevel::Warning);
1022 }
1023 let archive = args.iter().find_map(|p| if let MHGraphicsArg::Archive(a) = p {Some(a)} else {None})
1024 .and_then(|pair|
1025 parse_id(&pair.val,pair.key_range.start,&mut p.tokenizer).map(|a| (a,pair.val_range))
1026 );
1027 let mut rel_path = filepath.0.to_string();
1028 {
1029 if let Some(id) = archive.as_ref().map_or_else(||
1030 p.state.archive.as_ref().map(|a| a.archive_id()),
1031 |(a,_)| Some(a)
1032 ) {
1033 p.state.backend.with_local_archive(id,|a|
1034 if let Some(a) = a {
1035 let path = a.source_dir();
1036 let path = rel_path.as_str().split('/').fold(path,|p,s| p.join(s));
1037 if !img_exists(&path,&mut rel_path,|s| p.tokenizer.problem(filepath.1.start,s,DiagnosticLevel::Info)) {
1038 p.tokenizer.problem(filepath.1.start,format!("Image file {} not found",path.display()),DiagnosticLevel::Error);
1039 }
1040 }
1041 );
1042 }
1043 }
1044 let filepath = (rel_path.into(),filepath.1);
1045 MacroResult::Success(STeXToken::MHGraphics {
1046 filepath,full_range:mhgraphics.range,archive,
1047 token_range:mhgraphics.token_range,args
1048 })
1049 }
1050);
1051
1052optargtype! {parser =>
1053 SymdeclArg<T> {
1054 {Name = "name" : str}
1055 {Tp = "type": T*}
1056 {Df = "def": T*}
1057 {Return = "return": T*}
1058 {Style = "style": ()}
1059 {Assoc = "assoc": ()}
1060 {Role = "role": ()}
1061 {Argtypes = "argtypes": T*}
1062 {Reorder = "reorder": ()}
1063 {Args = "args": Args}
1064 } @ SymdeclArgIter
1065}
1066
1067stex!(p => symdecl('*'?star){name:!name}[args:type SymdeclArg<Pos,STeXToken<Pos>>] => {
1068 let macroname = if star {None} else {Some(&name.0)};
1069 let args = args.unwrap_or_default();
1070 let main_name_range = name.1;
1071 let mut name:(&str,_) = (&name.0,name.1);
1072 let mut has_df = false;
1073 let mut has_tp = false;
1074 let mut argnum = 0;
1075 for e in &args { match e {
1076 SymdeclArg::Name(ParsedKeyValue { val_range, val,.. }) => {
1077 name = (val,*val_range);
1078 }
1079 SymdeclArg::Tp(_) | SymdeclArg::Return(_) => has_tp = true,
1080 SymdeclArg::Df(_) => has_df = true,
1081 SymdeclArg::Args(v) => argnum = v.val,
1082 _ => ()
1083 }}
1084
1085 let (state,mut groups) = p.split();
1086 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1087 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1088 return MacroResult::Simple(symdecl)
1089 };
1090 let mn = macroname.as_ref();
1091 if let Some(uri) = state.add_symbol(&mut groups,fname,
1092 mn.map(|s| (*s).to_string().into()),
1093 symdecl.range,has_tp,has_df,argnum
1094 ) {
1095 MacroResult::Success(STeXToken::Symdecl {
1096 starred:star,
1097 uri, main_name_range,
1098 full_range:symdecl.range,parsed_args:args,
1099 token_range:symdecl.token_range
1100 })
1101 } else {
1102 MacroResult::Simple(symdecl)
1103 }
1104 }
1105);
1106
1107optargtype! {parser =>
1108 TextSymdeclArg<T> {
1109 {Name = "name" : str}
1110 {Style = "style": ()}
1111 {Tp = "type": T*}
1112 {Df = "def": T*}
1113 } @ TextSymdeclArgIter
1114}
1115
1116stex!(p => textsymdecl{name:name}[args:type TextSymdeclArg<Pos,STeXToken<Pos>>] => {
1117 let macroname = Some(name.0);
1118 let main_name_range = name.1;
1119 let args = args.unwrap_or_default();
1120 let mut name:(&str,_) = (&name.0,name.1);
1121 for e in &args { match e {
1124 TextSymdeclArg::Name(ParsedKeyValue { val_range, val,.. }) => {
1125 name = (val,*val_range);
1126 }
1127 _ => ()
1130 }}
1131
1132 let (state,mut groups) = p.split();
1133 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1134 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1135 return MacroResult::Simple(textsymdecl)
1136 };
1137 let mn = macroname.as_ref();
1138 if let Some(uri) = state.add_symbol(&mut groups,fname,
1139 mn.map(|s| (*s).to_string().into()),
1140 textsymdecl.range,false,false,0
1141 ) {
1142 MacroResult::Success(STeXToken::TextSymdecl {
1143 uri, main_name_range,
1144 full_range:textsymdecl.range,parsed_args:args,
1145 token_range:textsymdecl.token_range
1146 })
1147 } else {
1148 MacroResult::Simple(textsymdecl)
1149 }
1150}
1151);
1152
1153optargtype! {parser =>
1154 NotationArg<T> {
1155 {Prec = "prec": T*}
1156 {Op = "op": T*}
1157 _ = Id
1158 } @ NotationArgIter
1159}
1160
1161stex!(LSP: p => notation('*'?star){name:!name}[args:type NotationArg<LSPLineCol,STeXToken<LSPLineCol>>] => {
1162 let args = args.unwrap_or_default();
1163 let (state,mut groups) = p.split();
1164 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1165 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1166 return MacroResult::Simple(notation);
1167 };
1168 MacroResult::Success(STeXToken::Notation {
1169 uri:s,
1170 token_range:notation.token_range,
1171 name_range:name.1,
1172 notation_args:args,
1173 full_range:notation.range
1174 })
1175});
1176
1177optargtype! {parser =>
1178 SymdefArg<T> {
1179 {Name = "name" : str}
1180 {Tp = "type": T*}
1181 {Df = "def": T*}
1182 {Return = "return": T*}
1183 {Style = "style": ()}
1184 {Assoc = "assoc": ()}
1185 {Role = "role": ()}
1186 {Argtypes = "argtypes": T*}
1187 {Reorder = "reorder": ()}
1188 {Args = "args": Args}
1189 {Prec = "prec": T*}
1190 {Op = "op": T*}
1191 _ = Id
1192 } @ SymdefArgIter
1193}
1194
1195stex!(p => symdef{name:!name}[args:type SymdefArg<Pos,STeXToken<Pos>>] => {
1196 let macroname = Some(&name.0);
1197 let main_name_range = name.1;
1198 let args = args.unwrap_or_default();
1199 let mut name:(&str,_) = (&name.0,name.1);
1200 let mut has_df = false;
1201 let mut has_tp = false;
1202 let mut argnum = 0;
1203 for e in &args { match e {
1204 SymdefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1205 name = (val,*val_range);
1206 }
1207 SymdefArg::Tp(_) | SymdefArg::Return(_) => has_tp = true,
1208 SymdefArg::Df(_) => has_df = true,
1209 SymdefArg::Args(v) => argnum = v.val,
1210 _ => ()
1211 }}
1212
1213 let (state,mut groups) = p.split();
1214 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1215 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1216 return MacroResult::Simple(symdef)
1217 };
1218 let mn = macroname.as_ref();
1219 if let Some(uri) = state.add_symbol(&mut groups,fname,
1220 mn.map(|s| (*s).to_string().into()),
1221 symdef.range,has_tp,has_df,argnum
1222 ) {
1223 MacroResult::Success(STeXToken::Symdef {
1224 uri, main_name_range,
1225 full_range:symdef.range,parsed_args:args,
1226 token_range:symdef.token_range
1227 })
1228 } else {
1229 MacroResult::Simple(symdef)
1230 }
1231}
1232);
1233
1234stex!(LSP: p => precondition{dim:!name}{symbol:!name} => {
1235 let Ok(cogdim) = dim.0.parse() else {
1236 p.tokenizer.problem(dim.1.start,format!("Invalid cognitive dimension {}",dim.0),DiagnosticLevel::Error);
1237 return MacroResult::Simple(precondition);
1238 };
1239 let (state,mut groups) = p.split();
1240 if !groups.groups.iter().rev().any(|g| matches!(g.kind,GroupKind::Problem)) {
1241 groups.tokenizer.problem(symbol.1.start, "\\precondition is only allowed in a problem",DiagnosticLevel::Error);
1242 }
1243 let Some(s) = state.get_symbol(symbol.1.start,&mut groups,&symbol.0) else {
1244 groups.tokenizer.problem(symbol.1.start, format!("Unknown symbol {}",symbol.0),DiagnosticLevel::Error);
1245 return MacroResult::Simple(precondition);
1246 };
1247 MacroResult::Success(STeXToken::Precondition {
1248 uri:s, full_range: precondition.range, token_range: precondition.token_range, dim_range:dim.1,
1249 symbol_range:symbol.1,dim:cogdim
1250 })
1251});
1252
1253stex!(LSP: p => objective{dim:!name}{symbol:!name} => {
1254 let Ok(cogdim) = dim.0.parse() else {
1255 p.tokenizer.problem(dim.1.start,format!("Invalid cognitive dimension {}",dim.0),DiagnosticLevel::Error);
1256 return MacroResult::Simple(objective);
1257 };
1258 let (state,mut groups) = p.split();
1259 if !groups.groups.iter().rev().any(|g| matches!(g.kind,GroupKind::Problem)) {
1260 groups.tokenizer.problem(symbol.1.start, "\\objective is only allowed in a problem",DiagnosticLevel::Error);
1261 }
1262 let Some(s) = state.get_symbol(symbol.1.start,&mut groups,&symbol.0) else {
1263 groups.tokenizer.problem(symbol.1.start, format!("Unknown symbol {}",symbol.0),DiagnosticLevel::Error);
1264 return MacroResult::Simple(objective);
1265 };
1266 MacroResult::Success(STeXToken::Objective {
1267 uri:s, full_range: objective.range, token_range: objective.token_range, dim_range:dim.1,
1268 symbol_range:symbol.1,dim:cogdim
1269 })
1270});
1271
1272stex!(LSP: p => symref[mut args:Map]{name:!name}{text:T} => {
1273 let (state,mut groups) = p.split();
1274 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1275 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1276 return MacroResult::Simple(symref);
1277 };
1278 args.inner.remove(&"root");
1279 for (k,v) in args.inner.iter() {
1280 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1281 }
1282 MacroResult::Success(STeXToken::Symref {
1283 is_def:false,
1284 uri:s, full_range: symref.range, token_range: symref.token_range,
1285 name_range: name.1, text
1286 })
1287});
1288
1289stex!(LSP: p => definiendum[mut args:Map]{name:!name}{text:T!} => {
1290 let (state,mut groups) = p.split();
1291 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1292 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1293 return MacroResult::Simple(definiendum);
1294 };
1295 args.inner.remove(&"root");
1296 for (k,v) in args.inner.iter() {
1297 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1298 }
1299
1300p.state.module_store.add_verbalization(
1301 text.2,
1302 &s.first().expect("should be unreachable").uri,
1303 p.state.language
1304);
1305 MacroResult::Success(STeXToken::Symref {
1306 is_def:true,
1307 uri:s, full_range: definiendum.range, token_range: definiendum.token_range,
1308 name_range: name.1, text:(text.0,text.1)
1309 })
1310});
1311
1312stex!(LSP: p => symname[mut args:Map]{name:!name} => {
1313 let (state,mut groups) = p.split();
1314 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1315 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1316 return MacroResult::Simple(symname);
1317 };
1318 let pre = if let Some(val) = args.inner.remove(&"pre") {
1319 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1320 } else { None };
1321 let post = if let Some(val) = args.inner.remove(&"post") {
1322 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1323 } else { None };
1324 for (k,v) in args.inner.iter() {
1325 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1326 }
1327 MacroResult::Success(STeXToken::SymName {
1328 is_def:false,
1329 uri:s, full_range: symname.range, token_range: symname.token_range,
1330 name_range: name.1,
1331 mode: super::structs::SymnameMode::PrePost{ pre, post }
1332 })
1333});
1334
1335stex!(LSP: p => Symname[mut args:Map]{name:!name} => {
1336 let (state,mut groups) = p.split();
1337 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1338 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1339 return MacroResult::Simple(Symname);
1340 };
1341 let post = if let Some(val) = args.inner.remove(&"post") {
1342 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1343 } else { None };
1344 for (k,v) in args.inner.iter() {
1345 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1346 }
1347 MacroResult::Success(STeXToken::SymName {
1348 is_def:false,
1349 uri:s, full_range: Symname.range, token_range: Symname.token_range,
1350 name_range: name.1,
1351 mode: super::structs::SymnameMode::Cap{ post }
1352 })
1353});
1354
1355stex!(LSP: p => symnames[mut args:Map]{name:!name} => {
1356 let (state,mut groups) = p.split();
1357 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1358 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1359 return MacroResult::Simple(symnames);
1360 };
1361 let pre = if let Some(val) = args.inner.remove(&"pre") {
1362 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1363 } else { None };
1364 for (k,v) in args.inner.iter() {
1365 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1366 }
1367 MacroResult::Success(STeXToken::SymName {
1368 is_def:false,
1369 uri:s, full_range: symnames.range, token_range: symnames.token_range,
1370 name_range: name.1,
1371 mode: super::structs::SymnameMode::PostS{ pre }
1372 })
1373});
1374
1375stex!(LSP: p => Symnames{name:!name} => {
1376 let (state,mut groups) = p.split();
1377 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1378 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1379 return MacroResult::Simple(Symnames);
1380 };
1381 MacroResult::Success(STeXToken::SymName {
1382 is_def:false,
1383 uri:s, full_range: Symnames.range, token_range: Symnames.token_range,
1384 name_range: name.1,
1385 mode: super::structs::SymnameMode::CapAndPostS
1386 })
1387});
1388
1389stex!(LSP: p => definame[mut args:Map]{name:!name} => {
1390 let (state,mut groups) = p.split();
1391 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1392 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1393 return MacroResult::Simple(definame);
1394 };
1395 let pre = if let Some(val) = args.inner.remove(&"pre") {
1396 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1397 } else { None };
1398 let post = if let Some(val) = args.inner.remove(&"post") {
1399 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1400 } else { None };
1401 args.inner.remove(&"root");
1402 for (k,v) in args.inner.iter() {
1403 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1404 }
1405 let mode =super::structs::SymnameMode::PrePost{ pre, post };
1406 MacroResult::Success(STeXToken::SymName {
1413 is_def:true,
1414 uri:s, full_range: definame.range, token_range: definame.token_range,
1415 name_range: name.1,
1416 mode
1417 })
1418});
1419
1420stex!(LSP: p => Definame[mut args:Map]{name:!name} => {
1421 let (state,mut groups) = p.split();
1422 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1423 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1424 return MacroResult::Simple(Definame);
1425 };
1426 let post = if let Some(val) = args.inner.remove(&"post") {
1427 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1428 } else { None };
1429 for (k,v) in args.inner.iter() {
1430 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1431 }
1432 let mode = super::structs::SymnameMode::Cap{ post };
1433 MacroResult::Success(STeXToken::SymName {
1440 is_def:true,
1441 uri:s, full_range: Definame.range, token_range: Definame.token_range,
1442 name_range: name.1,
1443 mode
1444 })
1445});
1446
1447stex!(LSP: p => definames[mut args:Map]{name:!name} => {
1448 let (state,mut groups) = p.split();
1449 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1450 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1451 return MacroResult::Simple(definames);
1452 };
1453 let pre = if let Some(val) = args.inner.remove(&"pre") {
1454 Some((val.key_range,val.val_range,strip_comments(val.str).trim().to_string()))
1455 } else { None };
1456 for (k,v) in args.inner.iter() {
1457 p.tokenizer.problem(v.key_range.start, format!("Unknown argument {k}"),DiagnosticLevel::Error);
1458 }
1459 let mode = super::structs::SymnameMode::PostS{ pre };
1460 MacroResult::Success(STeXToken::SymName {
1467 is_def:true,
1468 uri:s, full_range: definames.range, token_range: definames.token_range,
1469 name_range: name.1,
1470 mode
1471 })
1472});
1473
1474stex!(LSP: p => Definames{name:!name} => {
1475 let (state,mut groups) = p.split();
1476 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1477 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1478 return MacroResult::Simple(Definames);
1479 };
1480 MacroResult::Success(STeXToken::SymName {
1487 is_def:true,
1488 uri:s, full_range: Definames.range, token_range: Definames.token_range,
1489 name_range: name.1,
1490 mode: super::structs::SymnameMode::CapAndPostS
1491 })
1492});
1493
1494stex!(LSP: p => symuse{name:!name} => {
1495 let (state,mut groups) = p.split();
1496 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1497 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1498 return MacroResult::Simple(symuse);
1499 };
1500 MacroResult::Success(STeXToken::Symuse {
1501 uri:s, full_range: symuse.range, token_range: symuse.token_range,
1502 name_range: name.1
1503 })
1504});
1505
1506stex!(LSP: p => defnotation => {
1507 MacroResult::Success(STeXToken::Defnotation{full_range:defnotation.token_range})
1508});
1509
1510stex!(LSP: p => definiens[name_opt:!name] => {
1511 let (state,mut groups) = p.split();
1512 let (s,rng) = if let Some(name) = name_opt {
1513 if let Some((s,_)) = get_in_morphism(groups.groups, &name.0) {
1514 (smallvec::smallvec![s.uri.clone()],Some(name.1))
1515 } else {
1516 let Some(s) = state.get_symbol(name.1.start,&mut groups,&name.0) else {
1517 p.tokenizer.problem(name.1.start, format!("Unknown symbol {}",name.0),DiagnosticLevel::Error);
1518 return MacroResult::Simple(definiens);
1519 };
1520 (s,Some(name.1))
1521 }
1522 } else {
1523 let Some(s) = groups.groups.iter().rev().find_map(|g|
1524 if let GroupKind::DefPara(defs) = &g.kind {
1525 defs.first().cloned()
1526 } else {None}
1527 ) else {
1528 p.tokenizer.problem(definiens.range.start, "No definition found".to_string(),DiagnosticLevel::Error);
1529 return MacroResult::Simple(definiens);
1530 };
1531 (smallvec::smallvec![s],None)
1532 };
1533 set_defined(s.first().unwrap_or_else(|| unreachable!()), definiens.range, groups.groups);
1534 MacroResult::Success(STeXToken::Definiens {
1535 uri:s, full_range: definiens.range, token_range: definiens.token_range,
1536 name_range: rng
1537 })
1538});
1539
1540stex!(LSP: p => defi_only => {
1541 p.tokenizer.problem(p.curr_pos(), "only allowed in definitions".to_string(),DiagnosticLevel::Error);
1542 MacroResult::Simple(defi_only)
1543});
1544
1545optargtype! {parser =>
1546 VardefArg<T> {
1547 {Name = "name" : str}
1548 {Args = "args": Args}
1549 {Tp = "type": T*}
1550 {Df = "def": T*}
1551 {Return = "return": T*}
1552 {Style = "style": ()}
1553 {Assoc = "assoc": ()}
1554 {Role = "role": ()}
1555 {Argtypes = "argtypes": T*}
1556 {Reorder = "reorder": ()}
1557 {Bind = "bind": !}
1558 {Prec = "prec": T*}
1559 {Op = "op": T*}
1560 _ = Id
1561 } @ VardefArgIter
1562}
1563
1564stex!(p => vardef{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1565 let macroname = name.0.to_string();
1566 let args = args.unwrap_or_default();
1567 let main_name_range = name.1;
1568 let mut name: (&str,_) = (&name.0,name.1);
1569 let mut argnum = 0;
1570
1571 for e in &args { match e {
1572 VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1573 name = (val,*val_range);
1574 }
1575 VardefArg::Args(v) => argnum = v.val,
1576 _ => ()
1577 }}
1578
1579 let (state,mut groups) = p.split();
1580 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1581 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1582 return MacroResult::Simple(vardef)
1583 };
1584 let rule = AnyMacro::Ext(DynMacro {
1585 ptr: variable_macro as _,
1586 arg:MacroArg::Variable(fname.clone(), vardef.range, false,argnum)
1587 });
1588 p.add_macro_rule(macroname.into(), Some(rule));
1589 MacroResult::Success(STeXToken::Vardef {
1590 name:fname, main_name_range,
1591 full_range:vardef.range,parsed_args:args,
1592 token_range:vardef.token_range
1593 })
1594});
1595
1596stex!(p => newvar{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1597 let macroname = format!("v{}",name.0);
1598 let args = args.unwrap_or_default();
1599 let main_name_range = name.1;
1600 let mut name: (&str,_) = (&name.0,name.1);
1601 let mut argnum = 0;
1602
1603 for e in &args { match e {
1604 VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1605 name = (val,*val_range);
1606 }
1607 VardefArg::Args(v) => argnum = v.val,
1608 _ => ()
1609 }}
1610
1611 let (state,mut groups) = p.split();
1612 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1613 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1614 return MacroResult::Simple(newvar)
1615 };
1616 let rule = AnyMacro::Ext(DynMacro {
1617 ptr: variable_macro as _,
1618 arg:MacroArg::Variable(fname.clone(), newvar.range, false,argnum)
1619 });
1620 p.add_macro_rule(macroname.into(), Some(rule));
1621 MacroResult::Success(STeXToken::Vardef {
1622 name:fname, main_name_range,
1623 full_range:newvar.range,parsed_args:args,
1624 token_range:newvar.token_range
1625 })
1626});
1627
1628stex!(p => varseq{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1629 let macroname = name.0.to_string();
1630 let args = args.unwrap_or_default();
1631 let main_name_range = name.1;
1632 let mut name : (&str,_) = (&name.0,name.1);
1633 let mut argnum = 0;
1636
1637 for e in &args { match e {
1638 VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1639 name = (val,*val_range);
1640 }
1641 VardefArg::Args(v) => argnum = v.val,
1644 _ => ()
1645 }}
1646
1647 let (state,mut groups) = p.split();
1648 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1649 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1650 return MacroResult::Simple(varseq)
1651 };
1652 let rule = AnyMacro::Ext(DynMacro {
1653 ptr: variable_macro as _,
1654 arg:MacroArg::Variable(fname.clone(), varseq.range, true,argnum)
1655 });
1656 p.add_macro_rule(macroname.into(), Some(rule));
1657 MacroResult::Success(STeXToken::Varseq {
1658 name:fname, main_name_range,
1659 full_range:varseq.range,parsed_args:args,
1660 token_range:varseq.token_range
1661 })
1662});
1663
1664stex!(p => newseq{name:!name}[args:type VardefArg<Pos,STeXToken<Pos>>] => {
1665let macroname = format!("v{}",name.0);
1666 let args = args.unwrap_or_default();
1667 let main_name_range = name.1;
1668 let mut name : (&str,_) = (&name.0,name.1);
1669 let mut argnum = 0;
1672
1673 for e in &args { match e {
1674 VardefArg::Name(ParsedKeyValue { key_range, val_range, val }) => {
1675 name = (val,*val_range);
1676 }
1677 VardefArg::Args(v) => argnum = v.val,
1680 _ => ()
1681 }}
1682
1683 let (state,mut groups) = p.split();
1684 let Ok(fname) : Result<UriName,_> = name.0.parse() else {
1685 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.0),DiagnosticLevel::Error);
1686 return MacroResult::Simple(newseq)
1687 };
1688 let rule = AnyMacro::Ext(DynMacro {
1689 ptr: variable_macro as _,
1690 arg:MacroArg::Variable(fname.clone(), newseq.range, true,argnum)
1691 });
1692 p.add_macro_rule(macroname.into(), Some(rule));
1693 MacroResult::Success(STeXToken::Varseq {
1694 name:fname, main_name_range,
1695 full_range:newseq.range,parsed_args:args,
1696 token_range:newseq.token_range
1697 })
1698});
1699
1700stex!(p => svar[optname:!name]{arg:!name} => {
1701 let (name,name_range) = if let Some(optname) = optname {
1702 (optname.0,Some(optname.1))
1703 } else {
1704 (arg.0,None)
1705 };
1706 let Ok(name) = name.as_ref().parse::<UriName>() else {
1707 p.tokenizer.problem(name_range.unwrap_or_default().start, format!("Invalid uri segment {name}"),DiagnosticLevel::Error);
1708 return MacroResult::Simple(svar)
1709 };
1710 MacroResult::Success(STeXToken::Svar {
1711 name, full_range:svar.range,name_range,arg_range:arg.1,
1712 token_range:svar.token_range
1713 })
1714});
1715
1716static META_REL_PATH: std::sync::LazyLock<std::sync::Arc<str>> =
1717 std::sync::LazyLock::new(|| "Metatheory.en.tex".into());
1718static META_FULL_PATH: std::sync::LazyLock<Option<std::sync::Arc<Path>>> =
1719 std::sync::LazyLock::new(|| {
1720 GlobalBackend.with_local_archive(ftml_uris::metatheory::URI.archive_id(), |a| {
1721 a.map(|a| a.source_dir().join("Metatheory.en.tex").into())
1722 })
1723 });
1724
1725fn get_module<'a, 'b, Pos: StringPosition + 'a, MS: STeXModuleStore>(
1726 p: &'b mut LaTeXParser<'a, Pos, STeXToken<Pos>, STeXParseState<'a, Pos, MS>>,
1727) -> Option<(&'b ModuleUri, &'b mut Vec<ModuleRule<Pos>>)> {
1728 p.groups.iter_mut().rev().find_map(|g| match &mut g.kind {
1729 GroupKind::Module { uri, rules } | GroupKind::MathStructure { uri, rules } => {
1730 Some((&*uri, rules))
1731 }
1732 _ => None,
1733 })
1734}
1735
1736optargtype!(parser =>
1737 SModuleArg<T> {
1738 {Sig = "sig": Language}
1739 {Meta = "meta": str}
1740 {Title = "title": T*}
1743 } @ SModuleArgIter
1744);
1745
1746stex!(LSP: p => @begin{smodule}([opt:type SModuleArg<LSPLineCol,STeXToken<LSPLineCol>>]{name:name}){
1747 let opt = opt.unwrap_or_default();
1748 let mut sig = None;
1749 let mut has_meta_theory = Some(false);
1750 for e in &opt { match e {
1751 SModuleArg::Sig(s) => sig = Some(s.val),
1752 SModuleArg::Meta(s) => {
1753 if s.val.is_empty() || &*s.val == "{}" {
1754 has_meta_theory = None;
1755 } else {
1756 p.tokenizer.problem(smodule.begin.range.start,"TODO: metatheory",DiagnosticLevel::Error);
1757 has_meta_theory = Some(true);
1758 }
1759 }
1760 SModuleArg::Title(_) => ()
1761 }}
1762 let meta_theory = if has_meta_theory == Some(false) {
1763 Some(ModuleReference {
1764 uri:ftml_uris::metatheory::URI.clone(),
1765 in_doc:ftml_uris::metatheory::DOC_URI.clone(),
1766 rel_path:Some(META_REL_PATH.clone()),
1767 full_path:META_FULL_PATH.clone()
1768 })
1769 } else { None };
1770
1771 let uri = if let Some((m,_)) = get_module(p) {
1772 name.0.parse().map(|n| m.clone() / &n).map_err(Into::into)
1773 } else {
1774 p.state.doc_uri.module_uri_from(name.0)
1775 };
1776 let Ok(uri) = uri else {
1777 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.1),DiagnosticLevel::Error);
1778 return ()
1779 };
1780 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Module{
1781 uri:uri.clone(),rules:Vec::new()
1782 };
1783 if let Some(l) = sig {
1784 if let Some(path) = &p.state.in_path {
1785 let curr_lang = p.state.language;
1786 let Some(filename) = path.file_name().and_then(|s| s.to_str()) else {
1787 p.tokenizer.problem(smodule.begin.range.start, "file path error", DiagnosticLevel::Error);
1788 return
1789 };
1790 let filename = {
1791 let Some(filename) = filename.strip_suffix(".tex") else {
1792 p.tokenizer.problem(smodule.begin.range.start, "file path error", DiagnosticLevel::Error);
1793 return
1794 };
1795 let init = if filename.ends_with(<&'static str>::from(curr_lang)) {
1796 &filename[..filename.len()-3]
1797 } else {filename};
1798 format!("{init}.{l}.tex")
1799 };
1800 let full_path = path.with_file_name(&filename);
1801 let rel_path = p.state.archive.as_ref().and_then(|a| {
1802 p.state.backend.with_local_archive(a.archive_id(), |a|
1803 a.and_then(|a| path.strip_prefix(a.path()).ok().and_then(|p|
1804 p.strip_prefix("source").ok().map(|p| p.with_file_name(filename).display().to_string().into())
1805 ))
1806 )
1807 });
1808
1809 let uri = uri.clone();
1810 let in_doc = p.state.doc_uri.path_uri().clone() & (p.state.doc_uri.document_name().clone(),l);
1811 let mrf = ModuleReference {
1812 uri,in_doc,rel_path,full_path:Some(full_path.into())
1813 };
1814 let (state,groups) = p.split();
1815 state.add_import(&mrf, groups, smodule.begin.range);
1816 }
1817 }
1818 if let Some(rf) = meta_theory.as_ref() {
1819 let (state,groups) = p.split();
1820 state.add_import(rf, groups, smodule.begin.range);
1822 }
1823 smodule.children.push(STeXToken::Module{
1824 uri,full_range:smodule.begin.range,sig,meta_theory,
1825 children:Vec::new(),name_range:name.1,
1826 smodule_range:smodule.name_range,opts:opt,
1827 rules:ModuleRules::default()
1828 });
1829 }{
1830 let Some(g) = p.groups.last_mut() else {
1831 p.tokenizer.problem(smodule.begin.range.start,"Module ended unexpectedly",DiagnosticLevel::Error);
1832 return EnvironmentResult::Simple(smodule)
1833 };
1834 let GroupKind::Module { uri, rules } = std::mem::take(&mut g.kind) else {
1835 return EnvironmentResult::Simple(smodule);
1836 };
1837 let rules = ModuleRules{ rules:rules.into()};
1838 p.state.modules.push((uri,rules.clone()));
1839 match smodule.children.first() {
1840 Some(STeXToken::Module { .. }) => {
1841 let mut ch = smodule.children.drain(..);
1842 let Some(STeXToken::Module { uri,mut full_range,sig,meta_theory,mut children,name_range,smodule_range,opts,.. }) = ch.next() else {
1843 unreachable!()
1844 };
1845 children.extend(ch);
1846 if let Some(end) = smodule.end {
1847 full_range.end = end.range.end;
1848 }
1849 EnvironmentResult::Success(STeXToken::Module { uri,rules,full_range,sig,meta_theory,children,name_range,smodule_range,opts })
1850 }
1851 _ => EnvironmentResult::Simple(smodule)
1852 }
1853 }
1854);
1855
1856optargtype!(parser =>
1857 MathStructureArg<T> {
1858 {This = "this": T*}
1859 _ = Name
1860 } @ MathStructureArgIter
1861);
1862
1863stex!(LSP: p => @begin{mathstructure}({name:!name}[args:type MathStructureArg<LSPLineCol,STeXToken<LSPLineCol>>]){
1864 let args = args.unwrap_or_default();
1865 let name_range = name.1;
1866 let macroname = &name.0;
1867 let mut name : &str = &name.0;
1868 for a in &args{ match a {
1869 MathStructureArg::Name(_,n) => name = n,
1870 MathStructureArg::This(_) => ()
1871 }}
1872
1873 let Ok(fname) : Result<UriName,_> = name.parse() else {
1874 p.tokenizer.problem(name_range.start, format!("Invalid uri segment {name}"),DiagnosticLevel::Error);
1875 return
1876 };
1877 let (state,mut groups) = p.split();
1878 let Some(uri) = state.add_structure(
1879 &mut groups,fname,Some(macroname.to_string().into()),mathstructure.begin.range
1880 ) else {
1881 return
1882 };
1883
1884 groups.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::MathStructure{
1885 uri:uri.uri.clone().into_module(),rules:Vec::new()
1886 };
1887
1888 mathstructure.children.push(STeXToken::MathStructure {
1889 uri, name_range,
1890 opts:args,
1891 mathstructure_range: mathstructure.name_range,
1892 full_range: mathstructure.begin.range,
1893 extends: Vec::new(),
1894 children: Vec::new()
1895 })
1896}{
1897 match mathstructure.children.first() {
1898 Some(STeXToken::MathStructure { .. }) => {
1899 let mut ch = mathstructure.children.drain(..);
1900 let Some(STeXToken::MathStructure { uri, opts, extends, name_range, mut full_range, mut children, mathstructure_range }) = ch.next() else{
1901 unreachable!()
1902 };
1903 children.extend(ch);
1904 if let Some(end) = mathstructure.end.as_ref() {
1905 full_range.end = end.range.end;
1906 }
1907
1908 let Some(g) = p.groups.last_mut() else {
1909 p.tokenizer.problem(mathstructure.begin.range.start,"Mathstructure ended unexpectedly",DiagnosticLevel::Error);
1910 return EnvironmentResult::Simple(mathstructure)
1911 };
1912 let GroupKind::MathStructure { uri:_, rules } = std::mem::take(&mut g.kind) else {
1913 return EnvironmentResult::Simple(mathstructure);
1914 };
1915 let rules = ModuleRules{ rules:rules.into()};
1916 let (state,mut groups) = p.split();
1917 state.set_structure(&mut groups, rules, full_range);
1918
1919 EnvironmentResult::Success(STeXToken::MathStructure {
1920 uri,extends,name_range,full_range,opts,children,mathstructure_range
1921 })
1922 }
1923 _ => {
1924 EnvironmentResult::Simple(mathstructure)
1925 }
1926 }
1927});
1928
1929stex!(LSP: p => @begin{extstructure}({name:!name}[args:type MathStructureArg<LSPLineCol,STeXToken<LSPLineCol>>]{exts:!name+}){
1930 let args = args.unwrap_or_default();
1931 let name_range = name.1;
1932 let macroname = &name.0;
1933 let mut name: &str = &name.0;
1934 for a in &args{ match a {
1935 MathStructureArg::Name(_,n) => name = n,
1936 MathStructureArg::This(_) => ()
1937 }}
1938
1939 let Ok(fname) : Result<UriName,_> = name.parse() else {
1940 p.tokenizer.problem(name_range.start, format!("Invalid uri segment {name}"),DiagnosticLevel::Error);
1941 return
1942 };
1943 let (state,mut groups) = p.split();
1944 let mut extends = Vec::new();
1945 for (n,r) in exts {
1946 let Some(s) = state.get_structure(&groups,&n) else {
1947 groups.tokenizer.problem(r.start, format!("Unknown structure {n}"),DiagnosticLevel::Error);
1948 return
1949 };
1950 extends.push((s.0,s.1,r));
1951 }
1952 let Some(uri) = state.add_structure(
1953 &mut groups,fname,Some(macroname.clone().into()),extstructure.begin.range
1954 ) else { return };
1955
1956 groups.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::MathStructure{
1957 uri:uri.uri.clone().into_module(),rules:Vec::new()
1958 };
1959
1960 for (s,r,_) in &extends {
1961 state.import_structure(s,r,&mut groups,extstructure.begin.range);
1962 }
1963
1964 extstructure.children.push(STeXToken::MathStructure {
1965 uri, name_range,
1966 opts:args,
1967 mathstructure_range: extstructure.name_range,
1968 full_range: extstructure.begin.range,
1969 extends:extends.into_iter().map(|(a,_,b)| (a,b)).collect(),
1970 children: Vec::new()
1971 })
1972}{
1973 match extstructure.children.first() {
1974 Some(STeXToken::MathStructure { .. }) => {
1975 let mut ch = extstructure.children.drain(..);
1976 let Some(STeXToken::MathStructure { uri,opts , extends, name_range, mut full_range, mut children, mathstructure_range }) = ch.next() else{
1977 unreachable!()
1978 };
1979 children.extend(ch);
1980 if let Some(end) = extstructure.end.as_ref() {
1981 full_range.end = end.range.end;
1982 }
1983
1984 let Some(g) = p.groups.last_mut() else {
1985 p.tokenizer.problem(extstructure.begin.range.start,"extstructure ended unexpectedly",DiagnosticLevel::Error);
1986 return EnvironmentResult::Simple(extstructure)
1987 };
1988 let GroupKind::MathStructure { uri:_, rules } = std::mem::take(&mut g.kind) else {
1989 return EnvironmentResult::Simple(extstructure);
1990 };
1991 let rules = ModuleRules{ rules:rules.into()};
1992 let (state,mut groups) = p.split();
1993 state.set_structure(&mut groups, rules, full_range);
1994
1995 EnvironmentResult::Success(STeXToken::MathStructure {
1996 uri,extends,name_range,full_range,opts,children,mathstructure_range
1997 })
1998 }
1999 _ => {
2000 EnvironmentResult::Simple(extstructure)
2001 }
2002 }
2003});
2004
2005stex!(LSP: p => @begin{extstructure_ast}({exts:!name}){
2006 let (state,mut groups) = p.split();
2007 let Some((sym,rules)) = state.get_structure(&groups,&exts.0) else {
2008 groups.tokenizer.problem(exts.1.start, format!("Unknown structure {}",exts.0),DiagnosticLevel::Error);
2009 return
2010 };
2011 let Some(uri) = state.add_conservative_ext(&mut groups, &sym, extstructure_ast.begin.range) else {
2012 groups.tokenizer.problem(exts.1.start, "Not in a module".to_string(),DiagnosticLevel::Error);
2013 return
2014 };
2015 groups.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::ConservativeExt(uri,Vec::new());
2016 state.use_structure(&sym,&rules,&mut groups,extstructure_ast.begin.range);
2017
2018 extstructure_ast.children.push(STeXToken::ConservativeExt {
2019 uri:sym, ext_range:exts.1,
2020 extstructure_range: extstructure_ast.name_range,
2021 full_range: extstructure_ast.begin.range,
2022 children: Vec::new()
2023 });
2024}{
2025 match extstructure_ast.children.first() {
2026 Some(STeXToken::ConservativeExt { .. }) => {
2027 let mut ch = extstructure_ast.children.drain(..);
2028 let Some(STeXToken::ConservativeExt { uri,ext_range, extstructure_range, mut full_range, mut children }) = ch.next() else{
2029 unreachable!()
2030 };
2031 children.extend(ch);
2032 if let Some(end) = extstructure_ast.end.as_ref() {
2033 full_range.end = end.range.end;
2034 }
2035
2036 let Some(g) = p.groups.last_mut() else {
2037 p.tokenizer.problem(extstructure_ast.begin.range.start,"extstructure* ended unexpectedly",DiagnosticLevel::Error);
2038 return EnvironmentResult::Simple(extstructure_ast)
2039 };
2040 let GroupKind::ConservativeExt(_,rules) = std::mem::take(&mut g.kind) else {
2041 return EnvironmentResult::Simple(extstructure_ast);
2042 };
2043 let rules = ModuleRules{ rules:rules.into()};
2044 let (state,mut groups) = p.split();
2045 state.set_structure(&mut groups, rules, full_range);
2046
2047 EnvironmentResult::Success(STeXToken::ConservativeExt {
2048 uri,ext_range,extstructure_range,full_range,children
2049 })
2050 }
2051 _ => {
2052 EnvironmentResult::Simple(extstructure_ast)
2053 }
2054 }
2055});
2056
2057stex!(p => @begin{smodule_deps}([opt]{name:name}){
2058 let opt = opt.as_keyvals();
2059 let sig = opt.get(&"sig").and_then(|v| v.val.parse().ok());
2060 let uri = if let Some((m,_)) = get_module(p) {
2061 name.0.parse().map(|n| m.clone() / &n).map_err(Into::into)
2062 } else {
2063 p.state.doc_uri.module_uri_from(name.0)
2064 };
2065 let Ok(uri) = uri else {
2066 p.tokenizer.problem(name.1.start, format!("Invalid uri segment {}",name.1),DiagnosticLevel::Error);
2067 return ()
2068 };
2069 let meta_theory = match opt.get(&"meta").map(|v| v.val) {
2070 None => Some(ModuleReference{
2071 uri:ftml_uris::metatheory::URI.clone(),
2072 in_doc:ftml_uris::metatheory::DOC_URI.clone(),
2073 rel_path:Some(META_REL_PATH.clone()),
2074 full_path:META_FULL_PATH.clone()
2075 }),
2076 Some(""|"{}") => None,
2077 Some(o) => None};
2079 smodule_deps.children.push(STeXToken::Module{
2081 uri,full_range:smodule_deps.begin.range,sig,meta_theory,
2082 children:Vec::new(),name_range:name.1,rules:ModuleRules::default(),
2083 smodule_range:smodule_deps.name_range,opts:Vec::new()
2084 });
2085 }{
2086 match smodule_deps.children.first() {
2088 Some(STeXToken::Module { .. }) => {
2089 let mut ch = smodule_deps.children.drain(..);
2090 let Some(STeXToken::Module { uri,mut full_range,sig,meta_theory,mut children,name_range,rules,smodule_range,opts }) = ch.next() else {
2091 unreachable!()
2092 };
2093 children.extend(ch);
2094 if let Some(end) = smodule_deps.end {
2095 full_range.end = end.range.end;
2096 }
2097 EnvironmentResult::Success(STeXToken::Module { uri,rules,full_range,sig,meta_theory,children,name_range,smodule_range,opts })
2098 }
2099 _ => EnvironmentResult::Simple(smodule_deps)
2100 }
2101 }
2102);
2103
2104optargtype! {LSP parser =>
2105 ParagraphArg<T> {
2106 {Id = "id": ()}
2107 {Name = "name": str}
2108 {MacroName = "macro": str}
2109 {Title = "title": T*}
2110 {Args = "args": Args}
2111 {Tp = "type": T*}
2112 {Df = "def": T*}
2113 {Return = "return": T*}
2114 {Style = "style": str}
2115 {Assoc = "assoc": ()}
2116 {Role = "role": ()}
2117 {From = "from": ()}
2118 {To = "to": ()}
2119 {Argtypes = "argtypes": T*}
2120 {Reorder = "reorder": ()}
2121 {Judgment = "judgment": ()}
2122 {Fors = "for": {Vec<(SmallVec<SymbolReference<Pos>,1>,StringRange<LSPLineCol>)> =>
2123 let strs = parser.read_value_strs_normalized();
2124 let (state,mut groups) = parser.parser.split();
2125 let ret = strs.into_iter().filter_map(|(name,range)|
2126 if let Some((symbol,_)) = get_in_morphism(&mut groups.groups, &name) {
2127 Some((smallvec::smallvec![symbol.uri.clone()],range))
2128 } else if let Some(symbol) = state.get_symbol(range.start,&mut groups, &name) {
2129 Some((symbol,range))
2130 } else {
2131 groups.tokenizer.problem(range.start,format!("Unknown symbol: {name}"),DiagnosticLevel::Error);
2132 None
2133 }
2134 ).collect();
2135 Some(Self::Fors(parser.to_key_value(ret)))
2136 }}
2137 } @ ParagraphArgIter
2138}
2139
2140fn do_def_macros<'a, MS: STeXModuleStore>(
2141 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2142) {
2143 p.add_macro_rule(
2144 Cow::Borrowed("definame"),
2145 Some(AnyMacro::Ptr(definame as _)),
2146 );
2147 p.add_macro_rule(
2148 Cow::Borrowed("Definame"),
2149 Some(AnyMacro::Ptr(Definame as _)),
2150 );
2151 p.add_macro_rule(
2152 Cow::Borrowed("definames"),
2153 Some(AnyMacro::Ptr(definames as _)),
2154 );
2155 p.add_macro_rule(
2156 Cow::Borrowed("Definames"),
2157 Some(AnyMacro::Ptr(Definames as _)),
2158 );
2159 p.add_macro_rule(
2160 Cow::Borrowed("definiendum"),
2161 Some(AnyMacro::Ptr(definiendum as _)),
2162 );
2163 p.add_macro_rule(
2164 Cow::Borrowed("defnotation"),
2165 Some(AnyMacro::Ptr(defnotation as _)),
2166 );
2167}
2168
2169fn do_paragraph<'a, MS: STeXModuleStore>(
2170 kind: ParagraphKind,
2171 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2172 range: StringRange<LSPLineCol>,
2173 open_group: bool,
2174) -> (
2175 Option<SymbolReference<LSPLineCol>>,
2176 Vec<ParagraphArg<LSPLineCol, STeXToken<LSPLineCol>>>,
2177) {
2178 let is_def_first = matches!(kind, ParagraphKind::Definition | ParagraphKind::Assertion);
2179 if open_group {
2180 p.open_group();
2181 }
2182 if is_def_first {
2183 p.add_macro_rule(
2184 Cow::Borrowed("definiens"),
2185 Some(AnyMacro::Ptr(definiens as _)),
2186 );
2187 if MS::FULL {
2188 do_def_macros(p);
2189 }
2190 }
2191
2192 let args =
2193 <Vec<ParagraphArg<_, _>> as crate::quickparse::latex::KeyValValues<_, _, _>>::parse_opt(p)
2194 .unwrap_or_default();
2195
2196 let mut name = None;
2197 let mut macroname = None;
2198 let mut argnum = 0;
2199 let mut has_tp = false;
2200 let mut has_def = false;
2201 let mut needs_name = false;
2202 let mut is_symdoc = false;
2203 let mut fors: &[_] = &[];
2204 for e in &args {
2205 match e {
2206 ParagraphArg::Name(n) => name = Some(&n.val),
2207 ParagraphArg::MacroName(n) => macroname = Some(&n.val),
2208 ParagraphArg::Args(n) => argnum = n.val,
2209 ParagraphArg::Tp(_) | ParagraphArg::Return(_) => has_tp = true,
2210 ParagraphArg::Df(_) => has_def = true,
2211 ParagraphArg::Argtypes(_)
2212 | ParagraphArg::Assoc(_)
2213 | ParagraphArg::Reorder(_)
2214 | ParagraphArg::Role(_) => needs_name = true,
2215 ParagraphArg::Style(s) if s.val.contains("symdoc") => is_symdoc = true,
2216 ParagraphArg::Fors(f) => fors = &f.val,
2217 _ => (),
2218 }
2219 }
2220
2221 let sym = if name.is_some() || macroname.is_some() {
2222 let fname = name.unwrap_or_else(|| macroname.unwrap_or_else(|| unreachable!()));
2223 let Ok(fname): Result<UriName, _> = fname.parse() else {
2224 p.tokenizer.problem(
2225 range.start,
2226 format!("Invalid uri segment {fname}"),
2227 DiagnosticLevel::Error,
2228 );
2229 return (None, args);
2230 };
2231 let (state, mut groups) = p.split();
2232 state.add_symbol(
2233 &mut groups,
2234 fname,
2235 macroname.map(|r| r.clone().into()),
2236 range,
2237 has_tp,
2238 has_def,
2239 argnum,
2240 )
2241 } else if argnum > 0 || has_tp || has_def || needs_name {
2242 p.tokenizer.problem(
2243 range.start,
2244 format!("Missing name or macroname"),
2245 DiagnosticLevel::Error,
2246 );
2247 None
2248 } else {
2249 None
2250 };
2251
2252 if !is_def_first && (sym.is_some() || matches!(kind,ParagraphKind::Paragraph if is_symdoc)) {
2253 p.add_macro_rule(
2254 Cow::Borrowed("definiens"),
2255 Some(AnyMacro::Ptr(definiens as _)),
2256 );
2257 if MS::FULL {
2258 do_def_macros(p);
2259 }
2260 }
2261
2262 let mut v: Vec<_> = fors
2263 .iter()
2264 .map(|(v, _)| v.first().unwrap_or_else(|| unreachable!()).clone())
2265 .collect();
2266 if let Some(s) = &sym {
2267 v.push(s.clone());
2268 }
2269 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::DefPara(v);
2270 (sym, args)
2271}
2272
2273fn inline_paragraph<'a, MS: STeXModuleStore>(
2274 kind: ParagraphKind,
2275 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2276 mut m: Macro<'a, LSPLineCol>,
2277 ) -> MacroResult<'a, LSPLineCol, STeXToken<LSPLineCol>> {
2279 let (sym, args) = do_paragraph(kind, p, m.range, true);
2280 let children = p.get_argument(&mut m);
2281 p.close_group();
2282 MacroResult::Success(STeXToken::InlineParagraph {
2283 kind,
2284 full_range: m.range,
2285 token_range: m.token_range,
2286 symbol: sym,
2287 parsed_args: args,
2288 children_range: children.0,
2289 children: children.1,
2290 })
2291}
2292
2293fn open_paragraph<'a, MS: STeXModuleStore>(
2294 kind: ParagraphKind,
2295 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2296 env: &mut Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2297) {
2298 let (sym, args) = do_paragraph(kind, p, env.begin.range, false);
2299 env.children.push(STeXToken::Paragraph {
2300 kind,
2301 full_range: env.begin.range,
2302 name_range: env.name_range,
2303 symbol: sym,
2304 parsed_args: args,
2305 children: Vec::new(),
2306 });
2307}
2308
2309fn close_paragraph<'a, MS: STeXModuleStore>(
2310 p: &LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2311 mut env: Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2312) -> EnvironmentResult<'a, LSPLineCol, STeXToken<LSPLineCol>> {
2313 match env.children.first() {
2314 Some(STeXToken::Paragraph { .. }) => {
2315 let mut ch = env.children.drain(..);
2316 let Some(STeXToken::Paragraph {
2317 kind,
2318 mut full_range,
2319 name_range,
2320 symbol,
2321 parsed_args,
2322 mut children,
2323 }) = ch.next()
2324 else {
2325 impossible!()
2326 };
2327 children.extend(ch);
2328 if let Some(end) = env.end.as_ref() {
2329 full_range.end = end.range.end;
2330 }
2331 EnvironmentResult::Success(STeXToken::Paragraph {
2332 kind,
2333 full_range,
2334 name_range,
2335 symbol,
2336 parsed_args,
2337 children,
2338 })
2339 }
2340 _ => EnvironmentResult::Simple(env),
2341 }
2342}
2343
2344stex!(LSP: p => @begin{sassertion}(){
2345 open_paragraph(ParagraphKind::Assertion, p, sassertion);
2346}{
2347 close_paragraph(p, sassertion)
2348});
2349
2350stex!(LSP: p => @begin{sdefinition}(){
2351 open_paragraph(ParagraphKind::Definition, p, sdefinition);
2352}{
2353 close_paragraph(p, sdefinition)
2354});
2355
2356stex!(LSP: p => @begin{sparagraph}(){
2357 open_paragraph(ParagraphKind::Paragraph, p, sparagraph);
2358}{
2359 close_paragraph(p, sparagraph)
2360});
2361
2362stex!(LSP: p => @begin{sexample}(){
2363 open_paragraph(ParagraphKind::Example, p, sexample);
2364}{
2365 close_paragraph(p, sexample)
2366});
2367
2368stex!(LSP: p => inlinedef => {
2369 inline_paragraph(ParagraphKind::Definition, p, inlinedef)
2370});
2371
2372stex!(LSP: p => inlineass => {
2373 inline_paragraph(ParagraphKind::Assertion, p, inlineass)
2374});
2375
2376stex!(LSP: p => inlinepara => {
2377 inline_paragraph(ParagraphKind::Paragraph, p, inlinepara)
2378});
2379
2380stex!(LSP: p => inlineex => {
2381 inline_paragraph(ParagraphKind::Example, p, inlineex)
2382});
2383
2384optargtype! {LSP parser =>
2385 ProblemArg<T> {
2386 {Id = "id": ()}
2387 {Title = "title": T*}
2388 {Style = "style": str}
2389 {Pts = "pts": f32}
2390 {Min = "min": f32}
2391 {Autogradable = "autogradable": bool?}
2393
2394 } @ ProblemArgIter
2395}
2396
2397fn open_problem<'a, MS: STeXModuleStore>(
2398 sub: bool,
2399 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2400 env: &mut Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2401) {
2402 let args =
2403 <Vec<ProblemArg<_, _>> as crate::quickparse::latex::KeyValValues<_, _, _>>::parse_opt(p)
2404 .unwrap_or_default();
2405 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Problem;
2406 env.children.push(STeXToken::Problem {
2407 sub,
2408 full_range: env.begin.range,
2409 name_range: env.name_range,
2410 parsed_args: args,
2411 children: Vec::new(),
2412 });
2413}
2414fn close_problem<'a, MS: STeXModuleStore>(
2415 p: &LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2416 mut env: Environment<'a, LSPLineCol, STeXToken<LSPLineCol>>,
2417) -> EnvironmentResult<'a, LSPLineCol, STeXToken<LSPLineCol>> {
2418 if let Some(STeXToken::Problem { .. }) = env.children.first() {
2419 let mut ch = env.children.drain(..);
2420 let Some(STeXToken::Problem {
2421 sub,
2422 mut full_range,
2423 parsed_args,
2424 name_range,
2425 mut children,
2426 }) = ch.next()
2427 else {
2428 impossible!()
2429 };
2430 children.extend(ch);
2431 if let Some(end) = env.end.as_ref() {
2432 full_range.end = end.range.end;
2433 }
2434 EnvironmentResult::Success(STeXToken::Problem {
2435 sub,
2436 full_range,
2437 name_range,
2438 parsed_args,
2439 children,
2440 })
2441 } else {
2442 EnvironmentResult::Simple(env)
2443 }
2444}
2445
2446stex!(LSP: p => @begin{sproblem}(){
2447 open_problem(false,p,sproblem)
2448}{
2449 close_problem(p,sproblem)
2450});
2451stex!(LSP: p => @begin{subproblem}(){
2452 open_problem(true,p,subproblem)
2453}{
2454 close_problem(p,subproblem)
2455});
2456
2457fn get_in_morphism<'b, MS: STeXModuleStore>(
2458 groups: &'b mut Vec<STeXGroup<'_, MS, LSPLineCol>>,
2459 name: &str,
2460) -> Option<(
2461 &'b SymbolRule<LSPLineCol>,
2462 &'b mut VecMap<SymbolReference<LSPLineCol>, MorphismSpec<LSPLineCol>>,
2463)> {
2464 for g in groups.iter_mut().rev() {
2465 if let GroupKind::Morphism {
2466 domain,
2467 rules,
2468 specs,
2469 } = &mut g.kind
2470 {
2471 let mut name = name;
2472 for (s, r) in &specs.0 {
2473 if r.macroname.as_ref().is_some_and(|n| &**n == name)
2474 || r.new_name.as_ref().is_some_and(|n| n.last() == name)
2475 {
2476 name = s.uri.name().last();
2477 break;
2478 }
2479 }
2480 for r in rules.iter().rev().flat_map(|r| r.rules.iter().rev()) {
2481 match r {
2482 ModuleRule::Symbol(s) | ModuleRule::Structure { symbol: s, .. }
2483 if s.macroname.as_ref().is_some_and(|n| &**n == name)
2484 || s.uri.uri.name().as_ref() == name =>
2485 {
2486 return Some((s, specs));
2487 }
2488 _ => (),
2489 }
2490 }
2491 break;
2492 }
2493 }
2494 None
2495}
2496
2497fn set_defined<MS: STeXModuleStore>(
2498 symbol: &SymbolReference<LSPLineCol>,
2499 range: StringRange<LSPLineCol>,
2500 groups: &mut Vec<STeXGroup<'_, MS, LSPLineCol>>,
2501) {
2502 for g in groups.iter_mut().rev() {
2503 match &mut g.kind {
2504 GroupKind::Morphism {
2505 domain,
2506 rules,
2507 specs,
2508 } => {
2509 let v = specs.get_or_insert_mut(symbol.clone(), MorphismSpec::default);
2510 v.is_assigned_at = Some(range);
2511 return;
2512 }
2513 GroupKind::Module { rules, .. }
2514 | GroupKind::ConservativeExt(_, rules)
2515 | GroupKind::MathStructure { rules, .. } => {
2516 for r in rules.iter_mut().rev() {
2517 match r {
2518 ModuleRule::Symbol(s) if s.uri.uri == symbol.uri => {
2519 s.has_df = true;
2520 return;
2521 }
2522 _ => (),
2523 }
2524 }
2525 return;
2526 }
2527 _ => (),
2528 }
2529 }
2530}
2531
2532stex!(LSP: p => renamedecl{orig:!name}[name:!name]{macroname:!name} => {
2533 let (_,mut groups) = p.split();
2534 let Some((symbol,specs)) = get_in_morphism(groups.groups, &orig.0) else {
2535 p.tokenizer.problem(renamedecl.range.start, format!("Could not find symbol {} in morphism",orig.0), DiagnosticLevel::Error);
2536 return MacroResult::Simple(renamedecl);
2537 };
2538 let uri = symbol.uri.clone();
2539 let spec = specs.get_or_insert_mut(uri.clone(), MorphismSpec::default);
2540 if spec.macroname.is_some() || spec.new_name.is_some() {
2541 p.tokenizer.problem(renamedecl.range.start, format!("Symbol {} already renamed in morphism",orig.0), DiagnosticLevel::Error);
2542 return MacroResult::Simple(renamedecl);
2543 }
2544 if let Some(name) = name.as_ref() {
2545 let Ok(name) = name.0.parse() else {
2546 p.tokenizer.problem(renamedecl.range.start, format!("Invalid name {}",name.0), DiagnosticLevel::Error);
2547 return MacroResult::Simple(renamedecl);
2548 };
2549 spec.new_name = Some(name);
2550 }
2551 spec.macroname = Some(macroname.0.to_string().into());
2552 if spec.decl_range == StringRange::default() {
2553 spec.decl_range = renamedecl.range;
2554 }
2555 MacroResult::Success(STeXToken::RenameDecl {
2556 uri, token_range: renamedecl.token_range, orig_range: orig.1,
2557 name_range: name.map(|(_,r)| r),
2558 macroname_range: macroname.1, full_range: renamedecl.range
2559 })
2560});
2561
2562stex!(LSP: p => assign{orig:!name} => {
2563 let (_,mut groups) = p.split();
2564 let Some((symbol,specs)) = get_in_morphism(groups.groups, &orig.0) else {
2565 p.tokenizer.problem(assign.range.start, format!("Could not find symbol {} in morphism",orig.0), DiagnosticLevel::Error);
2566 return MacroResult::Simple(assign);
2567 };
2568 let uri = symbol.uri.clone();
2569 let spec = specs.get_or_insert_mut(uri.clone(), MorphismSpec::default);
2570 if spec.is_assigned_at.is_some() {
2571 p.tokenizer.problem(assign.range.start, format!("Symbol {} already assigned in morphism",orig.0), DiagnosticLevel::Error);
2572 return MacroResult::Simple(assign);
2573 }
2574 if spec.decl_range == StringRange::default() {
2575 spec.decl_range = assign.range;
2576 }
2577 spec.is_assigned_at = Some(assign.range);
2578 MacroResult::Success(STeXToken::Assign {
2579 uri, token_range: assign.token_range, orig_range: orig.1,
2580 full_range: assign.range
2581 })
2582});
2583
2584fn define_assignment_macros<'a, MS: STeXModuleStore>(
2585 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2586) {
2587 p.add_macro_rule(
2588 Cow::Borrowed("renamedecl"),
2589 Some(AnyMacro::Ptr(renamedecl as _)),
2590 );
2591 p.add_macro_rule(Cow::Borrowed("assign"), Some(AnyMacro::Ptr(assign as _)));
2592}
2593
2594fn setup_morphism<'a, MS: STeXModuleStore>(
2595 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2596 name: &str,
2597 archive: &Option<(&'a str, StringRange<LSPLineCol>)>,
2598 domain: &str,
2599 pos: LSPLineCol,
2600) -> Option<(
2601 SymbolUri,
2602 ModuleOrStruct<LSPLineCol>,
2603 Vec<ModuleRules<LSPLineCol>>,
2604)> {
2605 let archive = archive.and_then(|(a, r)| parse_id(a, pos, &mut p.tokenizer));
2606 let (state, mut groups) = p.split();
2607
2608 let Ok(name) = name.parse::<UriName>() else {
2609 p.tokenizer.problem(
2610 pos,
2611 format!("Invalid module name: {name}"),
2612 DiagnosticLevel::Error,
2613 );
2614 return None;
2615 };
2616 let _ = state.add_symbol(
2617 &mut groups,
2618 name.clone(),
2619 None,
2620 StringRange {
2621 start: pos,
2622 end: pos,
2623 },
2624 false,
2625 true,
2626 0,
2627 );
2628 let Some((mors, rules)) = state.resolve_module_or_struct(&groups, domain, archive) else {
2629 groups.tokenizer.problem(
2630 pos,
2631 format!("No module or structure {domain} found"),
2632 DiagnosticLevel::Error,
2633 );
2634 return None;
2635 };
2636
2637 let Some((uri, _)) = get_module(p) else {
2638 p.tokenizer
2639 .problem(pos, "Not in a module", DiagnosticLevel::Error);
2640 return None;
2641 };
2642 Some((uri.clone() | name, mors, rules))
2643}
2644
2645fn elaborate_morphism<'a, MS: STeXModuleStore>(
2646 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2647 do_macros: bool,
2648 check_defined: bool,
2649 range: StringRange<LSPLineCol>,
2650 name: &str,
2651 rules: Vec<ModuleRules<LSPLineCol>>,
2652 mut specs: VecMap<SymbolReference<LSPLineCol>, MorphismSpec<LSPLineCol>>,
2653) {
2654 let old_end = std::mem::replace(&mut p.tokenizer.reader.pos, range.end);
2655 let Some(name) = name.parse::<UriName>().ok() else {
2656 p.tokenizer.problem(
2657 range.start,
2658 format!("Invalid name: {name}"),
2659 DiagnosticLevel::Error,
2660 );
2661 p.tokenizer.reader.pos = old_end;
2662 return;
2663 };
2664 let Some((in_module, _)) = get_module(p) else {
2665 p.tokenizer.problem(
2666 range.start,
2667 "Morphism only allowed in module",
2668 DiagnosticLevel::Error,
2669 );
2670 p.tokenizer.reader.pos = old_end;
2671 return;
2672 };
2673 let mut dones = Vec::new();
2674 let (state, mut groups) = p.split();
2675 for rls in &rules {
2676 for r in rls.rules.iter() {
2677 if let ModuleRule::Symbol(s) = r
2678 && !dones.contains(&&s.uri)
2679 {
2680 dones.push(&s.uri);
2681 let (macroname, name, dfed, rng) = if let Some(spec) = specs.remove(&s.uri) {
2682 let m = spec.macroname.map_or_else(
2683 || if do_macros { s.macroname.clone() } else { None },
2684 |m| Some(m.into()),
2685 );
2686 let n = spec.new_name.unwrap_or_else(|| &name / s.uri.uri.name());
2687 let d = spec.is_assigned_at.is_some() || s.has_df;
2688 (m, n, d, spec.decl_range)
2689 } else {
2690 let m = if do_macros { s.macroname.clone() } else { None };
2691 let n = &name / s.uri.uri.name();
2692 let d = s.has_df;
2693 (m, n, d, range)
2694 };
2695 if check_defined && !dfed {
2696 groups.tokenizer.problem(
2697 range.start,
2698 format!("{} not defined in total morphism", s.uri.uri),
2699 DiagnosticLevel::Error,
2700 );
2701 }
2702 if state
2703 .add_symbol(
2704 &mut groups,
2705 name,
2706 macroname,
2707 range,
2708 s.has_tp,
2709 dfed,
2710 s.argnum,
2711 )
2712 .is_none()
2713 {
2714 groups.tokenizer.problem(
2715 range.start,
2716 "Morphism only allowed in module",
2717 DiagnosticLevel::Error,
2718 );
2719 }
2720 }
2721 }
2722 }
2723 p.tokenizer.reader.pos = old_end;
2724}
2725
2726stex!(LSP: p => @begin{copymodule}({name:!name}[archive:str]{domain:!name}){
2728 let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,copymodule.begin.range.start) else { return };
2729 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
2730 define_assignment_macros(p);
2731 let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
2732 let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
2733 copymodule.children.push(STeXToken::MorphismEnv {
2734 kind:MorphismKind::CopyModule,
2735 domain:mors,uri,
2736 star:false,
2737 full_range:copymodule.begin.range,
2738 env_range:copymodule.name_range,
2739 domain_range,
2740 name_range:name.1,
2741 children:Vec::new()
2742 });
2743}{
2744 match copymodule.children.first() {
2745 Some(STeXToken::MorphismEnv{..}) => {
2746 let mut ch = copymodule.children.drain(..);
2747 let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
2748 unreachable!()
2749 };
2750 children.extend(ch);
2751 if let Some(end) =copymodule.end.as_ref() {
2752 full_range.end = end.range.end;
2753 }
2754 let Some(g) = p.groups.last_mut() else {
2755 p.tokenizer.problem(copymodule.begin.range.start,"copymodule ended unexpectedly",DiagnosticLevel::Error);
2756 return EnvironmentResult::Simple(copymodule)
2757 };
2758 let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
2759 return EnvironmentResult::Simple(copymodule);
2760 };
2761 elaborate_morphism(p,star,false,copymodule.begin.range,uri.name().last(),rules,specs);
2762 EnvironmentResult::Success(STeXToken::MorphismEnv {
2763 kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
2764 })
2765 }
2766 _ => EnvironmentResult::Simple(copymodule)
2767 }
2768});
2769
2770stex!(LSP: p => @begin{copymodule_ast}({name:!name}[archive:str]{domain:!name}){
2771 let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,copymodule_ast.begin.range.start) else { return };
2772 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
2773 define_assignment_macros(p);
2774 let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
2775 let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
2776 copymodule_ast.children.push(STeXToken::MorphismEnv {
2777 kind:MorphismKind::CopyModule,
2778 domain:mors,uri,
2779 star:true,
2780 full_range:copymodule_ast.begin.range,
2781 env_range:copymodule_ast.name_range,
2782 domain_range,
2783 name_range:name.1,
2784 children:Vec::new()
2785 });
2786}{
2787 match copymodule_ast.children.first() {
2788 Some(STeXToken::MorphismEnv{..}) => {
2789 let mut ch = copymodule_ast.children.drain(..);
2790 let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
2791 unreachable!()
2792 };
2793 children.extend(ch);
2794 if let Some(end) =copymodule_ast.end.as_ref() {
2795 full_range.end = end.range.end;
2796 }
2797 let Some(g) = p.groups.last_mut() else {
2798 p.tokenizer.problem(copymodule_ast.begin.range.start,"copymodule* ended unexpectedly",DiagnosticLevel::Error);
2799 return EnvironmentResult::Simple(copymodule_ast)
2800 };
2801 let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
2802 return EnvironmentResult::Simple(copymodule_ast);
2803 };
2804 elaborate_morphism(p,star,false,copymodule_ast.begin.range,uri.name().last(),rules,specs);
2805 EnvironmentResult::Success(STeXToken::MorphismEnv {
2806 kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
2807 })
2808 }
2809 _ => EnvironmentResult::Simple(copymodule_ast)
2810 }
2811});
2812
2813#[allow(clippy::too_many_lines)]
2814fn parse_assignments<'a, MS: STeXModuleStore>(
2815 p: &mut LaTeXParser<'a, LSPLineCol, STeXToken<LSPLineCol>, STeXParseState<'a, LSPLineCol, MS>>,
2816 m: &mut Macro<'a, LSPLineCol>,
2817) -> Option<(
2818 Vec<InlineMorphAssign<LSPLineCol, STeXToken<LSPLineCol>>>,
2819 VecMap<SymbolReference<LSPLineCol>, MorphismSpec<LSPLineCol>>,
2820)> {
2821 let mut specs = Vec::new();
2822 p.skip_comments();
2823 if !p.tokenizer.reader.starts_with('{') {
2824 p.tokenizer
2825 .problem(m.range.start, "Group expected", DiagnosticLevel::Error);
2826 return None;
2827 }
2828 p.tokenizer.reader.next_char();
2829 p.skip_comments();
2830 loop {
2831 if p.tokenizer.reader.starts_with('}') {
2832 p.tokenizer.reader.next_char();
2833 break;
2834 }
2835 let start = p.curr_pos();
2836 let symbol_name = p
2837 .tokenizer
2838 .reader
2839 .read_until(|c| c == '}' || c == ',' || c == '=' || c == '%' || c == '@')
2840 .trim();
2841 let symbol_range = StringRange {
2842 start,
2843 end: p.tokenizer.reader.curr_pos(),
2844 };
2845 let (state, groups) = p.split();
2846 let Some(symbol) = get_in_morphism(groups.groups, symbol_name).map(|(s, _)| s.uri.clone())
2847 else {
2848 groups.tokenizer.problem(
2849 symbol_range.start,
2850 format!("Symbol {symbol_name} not found in morphism"),
2851 DiagnosticLevel::Error,
2852 );
2853 return None;
2854 };
2855 p.skip_comments();
2856 let infix = p.curr_pos();
2857 macro_rules! def {
2858 () => {{
2859 p.skip_comments();
2860 let start = p.curr_pos();
2861 let txt = p
2862 .tokenizer
2863 .reader
2864 .read_until_with_brackets('{', '}', |c| c == ',' || c == '@' || c == '}');
2865 let ret = p.reparse(txt, start);
2866 p.skip_comments();
2867 ret
2868 }};
2869 }
2870 macro_rules! rename {
2871 () => {{
2872 p.skip_comments();
2873 let real_name = if p.tokenizer.reader.starts_with('[') {
2874 p.tokenizer.reader.next_char();
2875 let start = p.curr_pos();
2876 let namestr = p
2877 .tokenizer
2878 .reader
2879 .read_until(|c| c == ']' || c == '=' || c == ',' || c == '}' || c == '%');
2880 let range = StringRange {
2881 start,
2882 end: p.curr_pos(),
2883 };
2884 p.skip_comments();
2885 match p.tokenizer.reader.next_char() {
2886 Some(']') => (),
2887 _ => {
2888 p.tokenizer
2889 .problem(start, "']' expected", DiagnosticLevel::Error);
2890 return None;
2891 }
2892 }
2893 let range = StringRange {
2894 start,
2895 end: p.curr_pos(),
2896 };
2897 let Ok(name) = namestr.parse::<UriName>() else {
2898 p.tokenizer.problem(
2899 start,
2900 format!("Invalid name: {namestr}"),
2901 DiagnosticLevel::Error,
2902 );
2903 return None;
2904 };
2905 Some((name, range))
2906 } else {
2907 None
2908 };
2909 let start = p.curr_pos();
2910 let namestr = p
2911 .tokenizer
2912 .reader
2913 .read_until(|c| c == '=' || c == ',' || c == '}' || c == '%');
2914 let range = StringRange {
2915 start,
2916 end: p.curr_pos(),
2917 };
2918 p.skip_comments();
2919 (real_name, namestr.to_string().into(), range)
2920 }};
2921 }
2922 match p.tokenizer.reader.next_char() {
2923 Some('=') => {
2924 let ret = def!();
2925 let infix2 = p.curr_pos();
2926 match p.tokenizer.reader.next_char() {
2927 Some('}') => {
2928 specs.push(InlineMorphAssign {
2929 symbol,
2930 symbol_range,
2931 first: Some((infix, InlineMorphAssKind::Df(ret))),
2932 second: None,
2933 });
2934 break;
2935 }
2936 Some(',') => {
2937 specs.push(InlineMorphAssign {
2938 symbol,
2939 symbol_range,
2940 first: Some((infix, InlineMorphAssKind::Df(ret))),
2941 second: None,
2942 });
2943 p.skip_comments();
2944 }
2945 Some('@') => {
2946 let (real_name, macroname, mrange) = rename!();
2947 match p.tokenizer.reader.next_char() {
2948 Some('}') => {
2949 specs.push(InlineMorphAssign {
2950 symbol,
2951 symbol_range,
2952 first: Some((infix, InlineMorphAssKind::Df(ret))),
2953 second: Some((
2954 infix2,
2955 InlineMorphAssKind::Rename(real_name, macroname, mrange),
2956 )),
2957 });
2958 break;
2959 }
2960 Some(',') => {
2961 specs.push(InlineMorphAssign {
2962 symbol,
2963 symbol_range,
2964 first: Some((infix, InlineMorphAssKind::Df(ret))),
2965 second: Some((
2966 infix2,
2967 InlineMorphAssKind::Rename(real_name, macroname, mrange),
2968 )),
2969 });
2970 p.skip_comments();
2971 }
2972 _ => {
2973 p.tokenizer.problem(
2974 start,
2975 "'}' or ',' expected",
2976 DiagnosticLevel::Error,
2977 );
2978 return None;
2979 }
2980 }
2981 }
2982 _ => {
2983 p.tokenizer.problem(
2984 symbol_range.end,
2985 "'}', ',' or '@' expected",
2986 DiagnosticLevel::Error,
2987 );
2988 return None;
2989 }
2990 }
2991 }
2992 Some('@') => {
2993 let (real_name, macroname, mrange) = rename!();
2994 let infix2 = p.curr_pos();
2995 match p.tokenizer.reader.next_char() {
2996 Some('}') => {
2997 specs.push(InlineMorphAssign {
2998 symbol,
2999 symbol_range,
3000 first: Some((
3001 infix,
3002 InlineMorphAssKind::Rename(real_name, macroname, mrange),
3003 )),
3004 second: None,
3005 });
3006 break;
3007 }
3008 Some(',') => {
3009 specs.push(InlineMorphAssign {
3010 symbol,
3011 symbol_range,
3012 first: Some((
3013 infix,
3014 InlineMorphAssKind::Rename(real_name, macroname, mrange),
3015 )),
3016 second: None,
3017 });
3018 p.skip_comments();
3019 }
3020 Some('=') => {
3021 let ret = def!();
3022 match p.tokenizer.reader.next_char() {
3023 Some('}') => {
3024 specs.push(InlineMorphAssign {
3025 symbol,
3026 symbol_range,
3027 first: Some((
3028 infix,
3029 InlineMorphAssKind::Rename(real_name, macroname, mrange),
3030 )),
3031 second: Some((infix2, InlineMorphAssKind::Df(ret))),
3032 });
3033 break;
3034 }
3035 Some(',') => {
3036 specs.push(InlineMorphAssign {
3037 symbol,
3038 symbol_range,
3039 first: Some((
3040 infix,
3041 InlineMorphAssKind::Rename(real_name, macroname, mrange),
3042 )),
3043 second: Some((infix2, InlineMorphAssKind::Df(ret))),
3044 });
3045 p.skip_comments();
3046 }
3047 _ => {
3048 p.tokenizer.problem(
3049 start,
3050 "'}' or ',' expected",
3051 DiagnosticLevel::Error,
3052 );
3053 return None;
3054 }
3055 }
3056 }
3057 _ => {
3058 p.tokenizer
3059 .problem(start, "']' expected", DiagnosticLevel::Error);
3060 return None;
3061 }
3062 }
3063 }
3064 _ => {
3065 p.tokenizer.problem(
3066 symbol_range.end,
3067 "'@' or '=' expected",
3068 DiagnosticLevel::Error,
3069 );
3070 return None;
3071 }
3072 }
3073 }
3074 m.range.end = p.tokenizer.reader.curr_pos();
3075
3076 let mut nspecs = VecMap::new();
3077 for InlineMorphAssign {
3078 symbol,
3079 first,
3080 second,
3081 ..
3082 } in &specs
3083 {
3084 let mut spec = MorphismSpec::default();
3085 if let Some((_, first)) = first {
3086 match first {
3087 InlineMorphAssKind::Df(_) => spec.is_assigned_at = Some(m.range),
3088 InlineMorphAssKind::Rename(rn, n, _) => {
3089 spec.macroname = Some(n.clone());
3090 if let Some((n, r)) = rn {
3091 spec.new_name = Some(n.clone());
3092 }
3093 }
3094 }
3095 }
3096 if let Some((_, second)) = second {
3097 match second {
3098 InlineMorphAssKind::Df(_) => spec.is_assigned_at = Some(m.range),
3099 InlineMorphAssKind::Rename(rn, n, _) => {
3100 spec.macroname = Some(n.clone());
3101 if let Some((n, r)) = rn {
3102 spec.new_name = Some(n.clone());
3103 }
3104 }
3105 }
3106 }
3107 nspecs.insert(symbol.clone(), spec);
3108 }
3109
3110 Some((specs, nspecs))
3111}
3112
3113stex!(LSP: p => copymod('*'?star){name:!name}[archive:str]{domain:!name} => {
3114 let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,copymod.range.start) else {
3115 return MacroResult::Simple(copymod)
3116 };
3117 p.open_group();
3118 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors, rules, specs: VecMap::default() };
3119 let Some((v,specs)) = parse_assignments(p, &mut copymod) else {
3120 return MacroResult::Simple(copymod)
3121 };
3122 let GroupKind::Morphism { domain: mors, rules, .. } = std::mem::take(&mut p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind) else { unreachable!()};
3123 p.close_group();
3124 elaborate_morphism(p, star, false, copymod.range, &name.0, rules, specs);
3125
3126 MacroResult::Success(STeXToken::InlineMorphism {
3127 full_range: copymod.range, token_range: copymod.token_range,
3128 name_range: name.1, uri, star, domain: mors, domain_range: domain.1,
3129 kind: MorphismKind::CopyModule, assignments: v
3130 })
3131});
3132
3133stex!(LSP: p => interpretmod('*'?star){name:!name}[archive:str]{domain:!name} => {
3134 let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,interpretmod.range.start) else {
3135 return MacroResult::Simple(interpretmod)
3136 };
3137 p.open_group();
3138 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors, rules, specs: VecMap::default() };
3139 let Some((v,specs)) = parse_assignments(p, &mut interpretmod) else {
3140 return MacroResult::Simple(interpretmod)
3141 };
3142 let GroupKind::Morphism { domain: mors, rules, .. } = std::mem::take(&mut p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind) else { unreachable!()};
3143 p.close_group();
3144 elaborate_morphism(p, star, true, interpretmod.range, &name.0, rules, specs);
3145
3146 MacroResult::Success(STeXToken::InlineMorphism {
3147 full_range: interpretmod.range, token_range: interpretmod.token_range,
3148 name_range: name.1, uri, star, domain: mors, domain_range: domain.1,
3149 kind: MorphismKind::CopyModule, assignments: v
3150 })
3151});
3152
3153stex!(LSP: p => @begin{interpretmodule}({name:!name}[archive:str]{domain:!name}){
3155 let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,interpretmodule.begin.range.start) else { return };
3156 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
3157 define_assignment_macros(p);
3158 let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
3159 let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
3160 interpretmodule.children.push(STeXToken::MorphismEnv {
3161 kind:MorphismKind::InterpretModule,
3162 domain:mors,uri,
3163 star:false,
3164 full_range:interpretmodule.begin.range,
3165 env_range:interpretmodule.name_range,
3166 domain_range,
3167 name_range:name.1,
3168 children:Vec::new()
3169 });
3170}{
3171 match interpretmodule.children.first() {
3172 Some(STeXToken::MorphismEnv{..}) => {
3173 let mut ch = interpretmodule.children.drain(..);
3174 let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
3175 unreachable!()
3176 };
3177 children.extend(ch);
3178 if let Some(end) = interpretmodule.end.as_ref() {
3179 full_range.end = end.range.end;
3180 }
3181 let Some(g) = p.groups.last_mut() else {
3182 p.tokenizer.problem(interpretmodule.begin.range.start,"interpretmodule ended unexpectedly",DiagnosticLevel::Error);
3183 return EnvironmentResult::Simple(interpretmodule)
3184 };
3185 let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
3186 return EnvironmentResult::Simple(interpretmodule);
3187 };
3188 elaborate_morphism(p,star,true,interpretmodule.begin.range,uri.name().last(),rules,specs);
3189 EnvironmentResult::Success(STeXToken::MorphismEnv {
3190 kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
3191 })
3192 }
3193 _ => EnvironmentResult::Simple(interpretmodule)
3194 }
3195});
3196
3197stex!(LSP: p => @begin{interpretmodule_ast}({name:!name}[archive:str]{domain:!name}){
3198 let Some((uri,mors,rules)) = setup_morphism(p, &name.0,&archive,&domain.0,interpretmodule_ast.begin.range.start) else { return };
3199 p.groups.last_mut().unwrap_or_else(|| unreachable!()).kind = GroupKind::Morphism { domain: mors.clone(), rules, specs: VecMap::default() };
3200 define_assignment_macros(p);
3201 let dom_range_start = archive.map_or(domain.1.start,|(_,r)| r.start);
3202 let domain_range = StringRange{ start:dom_range_start, end:domain.1.end};
3203 interpretmodule_ast.children.push(STeXToken::MorphismEnv {
3204 kind:MorphismKind::InterpretModule,
3205 domain:mors,uri,
3206 star:true,
3207 full_range:interpretmodule_ast.begin.range,
3208 env_range:interpretmodule_ast.name_range,
3209 domain_range,
3210 name_range:name.1,
3211 children:Vec::new()
3212 });
3213}{
3214 match interpretmodule_ast.children.first() {
3215 Some(STeXToken::MorphismEnv{..}) => {
3216 let mut ch = interpretmodule_ast.children.drain(..);
3217 let Some(STeXToken::MorphismEnv { mut full_range, star,env_range, name_range, uri, domain, domain_range, kind, mut children }) = ch.next() else {
3218 unreachable!()
3219 };
3220 children.extend(ch);
3221 if let Some(end) = interpretmodule_ast.end.as_ref() {
3222 full_range.end = end.range.end;
3223 }
3224 let Some(g) = p.groups.last_mut() else {
3225 p.tokenizer.problem(interpretmodule_ast.begin.range.start,"interpretmodule ended unexpectedly",DiagnosticLevel::Error);
3226 return EnvironmentResult::Simple(interpretmodule_ast)
3227 };
3228 let GroupKind::Morphism{domain,rules,specs} = std::mem::take(&mut g.kind) else {
3229 return EnvironmentResult::Simple(interpretmodule_ast);
3230 };
3231 elaborate_morphism(p,star,true,interpretmodule_ast.begin.range,uri.name().last(),rules,specs);
3232 EnvironmentResult::Success(STeXToken::MorphismEnv {
3233 kind, full_range, name_range, star,env_range,uri,domain,domain_range,children
3234 })
3235 }
3236 _ => EnvironmentResult::Simple(interpretmodule_ast)
3237 }
3238});
3239
3240#[allow(clippy::needless_pass_by_value)]
3241pub(super) fn semantic_macro<'a, MS: STeXModuleStore, Pos: StringPosition + 'a>(
3242 arg: &MacroArg<Pos>, m: Macro<'a, Pos>,
3244 _parser: &mut LaTeXParser<'a, Pos, STeXToken<Pos>, STeXParseState<'a, Pos, MS>>,
3245) -> MacroResult<'a, Pos, STeXToken<Pos>> {
3246 let MacroArg::Symbol(uri, argnum) = arg else {
3247 unreachable!()
3248 };
3249 MacroResult::Success(STeXToken::SemanticMacro {
3250 uri: uri.clone(),
3251 argnum: *argnum,
3252 full_range: m.range,
3253 token_range: m.token_range,
3254 })
3255}
3256
3257pub(super) fn variable_macro<'a, MS: STeXModuleStore, Pos: StringPosition + 'a>(
3258 arg: &MacroArg<Pos>, m: Macro<'a, Pos>,
3260 _parser: &mut LaTeXParser<'a, Pos, STeXToken<Pos>, STeXParseState<'a, Pos, MS>>,
3261) -> MacroResult<'a, Pos, STeXToken<Pos>> {
3262 let MacroArg::Variable(name, range, seq, argnum) = arg else {
3263 unreachable!()
3264 };
3265 MacroResult::Success(STeXToken::VariableMacro {
3266 name: name.clone(),
3267 full_range: m.range,
3268 token_range: m.token_range,
3269 sequence: *seq,
3270 orig: *range,
3271 argnum: *argnum,
3272 })
3273}