1pub mod point;
2
3use core::fmt;
4use core::fmt::Display;
5use std::collections::HashMap;
6use std::convert::{TryFrom, TryInto};
7use std::fmt::Formatter;
8use std::marker::PhantomData;
9use std::ops;
10use std::ops::{Deref, Range, RangeFrom, RangeTo};
11use std::rc::Rc;
12use std::str::FromStr;
13use std::sync::Arc;
14
15use nom::branch::alt;
17use nom::bytes::complete::take;
18use nom::bytes::complete::{escaped, is_a, is_not};
19use nom::bytes::complete::{tag, take_till, take_until, take_until1, take_while};
20use nom::character::complete::{
21 alpha0, alphanumeric0, alphanumeric1, anychar, char, digit0, line_ending, multispace0,
22 multispace1, newline, one_of, satisfy, space0, space1,
23};
24use nom::character::complete::{alpha1, digit1};
25use nom::character::is_space;
26use nom::combinator::{all_consuming, opt};
27use nom::combinator::{cut, eof, fail, not, peek, recognize, success, value, verify};
28use nom::error::{context, ContextError, ErrorKind, ParseError, VerboseError};
29use nom::multi::{many0, many1, separated_list0};
30use nom::sequence::{delimited, pair, preceded, terminated, tuple};
31use nom::{
32 AsChar, Compare, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset,
33 Parser, Slice,
34};
35use nom::{Err, IResult};
36use nom_locate::LocatedSpan;
37use nom_supreme::error::ErrorTree;
38use nom_supreme::final_parser::ExtractContext;
39use nom_supreme::parser_ext::MapRes;
40use nom_supreme::{parse_from_str, ParserExt};
41use regex::{Captures, Error, Match, Regex};
42use serde::{Deserialize, Deserializer, Serialize, Serializer};
43
44use cosmic_nom::{new_span, span_with_extra, Trace};
45use cosmic_nom::{Res, Span, trim, tw, Wrap};
46
47use crate::command::common::{PropertyMod, SetProperties, StateSrc, StateSrcVar};
48use crate::command::direct::create::{
49 Create, CreateVar, KindTemplate, PointSegTemplate, PointTemplate, PointTemplateSeg,
50 PointTemplateVar, Require, Strategy, Template, TemplateVar,
51};
52use crate::command::direct::get::{Get, GetOp, GetVar};
53use crate::command::direct::select::{Select, SelectIntoSubstance, SelectKind, SelectVar};
54use crate::command::direct::set::{Set, SetVar};
55use crate::command::direct::CmdKind;
56use crate::command::CommandVar;
57use crate::config::bind::{
58 BindConfig, Pipeline, PipelineStep, PipelineStepCtx, PipelineStepVar, PipelineStop,
59 PipelineStopCtx, PipelineStopVar, RouteSelector, WaveDirection,
60};
61use crate::config::mechtron::MechtronConfig;
62use crate::config::Document;
63use crate::err::report::{Label, Report, ReportKind};
64use crate::err::{ParseErrs, SpaceErr};
65use crate::kind::{
66 ArtifactSubKind, BaseKind, DatabaseSubKind, FileSubKind, Kind, KindParts, NativeSub, Specific,
67 StarSub, UserBaseSubKind,
68};
69use crate::loc::StarKey;
70use crate::loc::{
71 Layer, PointSegment,
72 Surface, Topic, Uuid, Variable, VarVal, Version,
73};
74use crate::parse::error::{find_parse_err, result};
75use crate::parse::model::{
76 BindScope, BindScopeKind, Block, BlockKind, Chunk, DelimitedBlockKind, LexBlock,
77 LexParentScope, LexRootScope, LexScope, LexScopeSelector, LexScopeSelectorAndFilters,
78 MechtronScope, MessageScopeSelectorAndFilters, NestedBlockKind, PipelineCtx, PipelineSegment,
79 PipelineSegmentCtx, PipelineSegmentVar, PipelineVar, RootScopeSelector, RouteScope,
80 ScopeFilterDef, ScopeFilters, ScopeFiltersDef, ScopeSelectorAndFiltersDef, Spanned, Subst,
81 TerminatedBlockKind, TextType, Var, VarParser,
82};
83use crate::particle::{PointKind, PointKindVar};
84use crate::point::{Point, PointCtx, PointSeg, PointSegCtx, PointSegDelim, PointSegVar, PointVar, RouteSeg, RouteSegVar};
85use crate::security::{
86 AccessGrantKind, AccessGrantKindDef, ChildPerms, ParticlePerms, Permissions, PermissionsMask,
87 PermissionsMaskKind, Privilege,
88};
89use crate::selector::specific::{ProductSelector, VariantSelector, VendorSelector};
90use crate::selector::{
91 ExactPointSeg, Hop, KindBaseSelector, KindSelector, LabeledPrimitiveTypeDef, MapEntryPattern,
92 MapEntryPatternCtx, MapEntryPatternVar, Pattern, PatternBlock, PatternBlockCtx,
93 PatternBlockVar, PayloadBlock, PayloadBlockCtx, PayloadBlockVar, PayloadType2Def,
94 PointHierarchy, PointKindSeg, PointSegSelector, Selector, SelectorDef, SpecificSelector,
95 SubKindSelector, UploadBlock, VersionReq,
96};
97use crate::substance::Bin;
98use crate::substance::{
99 Call, CallCtx, CallKind, CallVar, CallWithConfig, CallWithConfigCtx, CallWithConfigVar,
100 ExtCall, HttpCall, ListPattern, MapPattern, MapPatternCtx, MapPatternVar, NumRange, Substance,
101 SubstanceFormat, SubstanceKind, SubstancePattern, SubstancePatternCtx, SubstancePatternVar,
102 SubstanceTypePatternCtx, SubstanceTypePatternDef, SubstanceTypePatternVar,
103};
104use crate::util::{HttpMethodPattern, StringMatcher, ToResolved, ValuePattern};
105use crate::wave::core::cmd::CmdMethod;
106use crate::wave::core::ext::ExtMethod;
107use crate::wave::core::http2::HttpMethod;
108use crate::wave::core::hyp::HypMethod;
109use crate::wave::core::MethodKind;
110use crate::wave::core::{Method, MethodPattern};
111
112fn any_resource_path_segment<T>(i: T) -> Res<T, T>
128where
129 T: InputTakeAtPosition + nom::InputLength,
130 <T as InputTakeAtPosition>::Item: AsChar,
131{
132 i.split_at_position1_complete(
133 |item| {
134 let char_item = item.as_char();
135 !(char_item == '-')
136 && !(char_item == '.')
137 && !(char_item == '/')
138 && !(char_item == '_')
139 && !(char_item.is_alpha() || char_item.is_dec_digit())
140 },
141 ErrorKind::AlphaNumeric,
142 )
143}
144
145fn sys_route_chars<T>(i: T) -> Res<T, T>
146where
147 T: InputTakeAtPosition + nom::InputLength,
148 <T as InputTakeAtPosition>::Item: AsChar,
149{
150 i.split_at_position1_complete(
151 |item| {
152 let char_item = item.as_char();
153 !(char_item == '-')
154 && !(char_item == '.')
155 && !(char_item == '/')
156 && !(char_item == '_')
157 && !(char_item == ':')
158 && !(char_item == '(')
159 && !(char_item == ')')
160 && !(char_item == '[')
161 && !(char_item == ']')
162 && !(char_item.is_alpha() || char_item.is_dec_digit())
163 },
164 ErrorKind::AlphaNumeric,
165 )
166}
167
168pub fn this_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
169 alt((recognize(tag(".")), recognize(not(other_route_segment))))(input)
170 .map(|(next, _)| (next, RouteSeg::This))
171}
172
173pub fn local_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
174 tag("LOCAL")(input).map(|(next, _)| (next, RouteSeg::Local))
175}
176
177pub fn remote_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
178 tag("REMOTE")(input).map(|(next, _)| (next, RouteSeg::Remote))
179}
180
181pub fn global_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
182 tag("GLOBAL")(input).map(|(next, _)| (next, RouteSeg::Global))
183}
184
185pub fn domain_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
186 domain_chars(input).map(|(next, domain)| (next, RouteSeg::Domain(domain.to_string())))
187}
188
189pub fn tag_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
190 delimited(tag("["), skewer_chars, tag("]"))(input)
191 .map(|(next, tag)| (next, RouteSeg::Tag(tag.to_string())))
192}
193
194pub fn sys_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
195 delimited(tag("<<"), sys_route_chars, tag(">>"))(input)
196 .map(|(next, tag)| (next, RouteSeg::Star(tag.to_string())))
197}
198
199pub fn other_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
200 alt((
201 sys_route_segment,
202 tag_route_segment,
203 domain_route_segment,
204 global_route_segment,
205 local_route_segment,
206 remote_route_segment,
207 ))(input)
208}
209
210pub fn point_route_segment<I: Span>(input: I) -> Res<I, RouteSeg> {
211 alt((this_route_segment, other_route_segment))(input)
212}
213
214pub fn mesh_eos<I: Span>(input: I) -> Res<I, I> {
228 peek(alt((tag(":"), eop)))(input)
229}
230
231pub fn fs_trailing<I: Span>(input: I) -> Res<I, I> {
232 peek(pair(
233 recognize(tag(":")),
234 context("point:version:root_not_trailing", cut(tag("/"))),
235 ))(input)
236 .map(|(next, (rtn, _))| (next, rtn))
237}
238
239pub fn ver_eos<I: Span>(input: I) -> Res<I, I> {
241 peek(alt((fs_trailing, tag(":/"), eop)))(input)
242}
243
244pub fn eop<I: Span>(input: I) -> Res<I, I> {
246 peek(alt((
247 eof,
248 multispace1,
249 tag("<"),
250 tag("\""),
251 tag("'"),
252 tag("]"),
253 tag(")"),
254 tag("}"),
255 tag("^"),
256 tag("["),
257 tag("("),
258 tag("{"),
259 tag("%"),
260 )))(input)
261}
262
263pub fn space_no_dupe_dots<I: Span>(input: I) -> Res<I, ()> {
264 context(
265 "point:space_segment:dot_dupes",
266 peek(cut(not(take_until("..")))),
267 )(input)
268 .map(|(next, _)| (next, ()))
269}
270
271pub fn space_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
272 context(
273 "point:space_segment",
274 cut(pair(
275 recognize(tuple((
276 context("point:space_segment_leading", peek(alpha1)),
277 space_no_dupe_dots,
278 space_chars,
279 ))),
280 mesh_eos,
281 )),
282 )(input)
283 .map(|(next, (space, x))| (next, PointSeg::Space(space.to_string())))
284}
285
286pub fn base_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
287 preceded(
288 peek(lowercase1),
289 context("point:base_segment", cut(pair(rec_skewer, mesh_eos))),
290 )(input)
291 .map(|(next, (base, _))| (next, PointSeg::Base(base.to_string())))
292}
293
294pub fn version_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
295 preceded(
296 peek(digit1),
297 context("point:version_segment", cut(tuple((version, ver_eos)))),
298 )(input)
299 .map(|(next, (version, _))| (next, PointSeg::Version(version)))
300}
301
302pub fn dir_pop<I: Span>(input: I) -> Res<I, PointSegVar> {
303 context("point:dir_pop", tuple((tag(".."), opt(tag("/")))))(input).map(|(next, _)| {
304 (
305 next.clone(),
306 PointSegVar::Pop(Trace {
307 range: next.location_offset() - 2..next.location_offset(),
308 extra: next.extra(),
309 }),
310 )
311 })
312}
313
314pub fn filesystem_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
315 tuple((
316 peek(not(eop)),
317 context(
318 "point:file_or_directory",
319 cut(alt((dir_point_segment, file_point_segment))),
320 ),
321 ))(input)
322 .map(|(next, (_, seg))| (next, seg))
323}
324
325pub fn dir_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
326 context("point:dir_segment", file_chars)(input)
327 .map(|(next, dir)| (next, PointSeg::Dir(dir.to_string())))
328}
329
330pub fn root_dir_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
331 context("point:root_filesystem_segment", tag(":/"))(input)
332 .map(|(next, _)| (next, PointSeg::FilesystemRootDir))
333}
334
335pub fn root_dir_point_segment_ctx<I: Span>(input: I) -> Res<I, PointSegVar> {
336 context("point:root_filesystem_segment", tag(":/"))(input)
337 .map(|(next, _)| (next, PointSegVar::FilesystemRootDir))
338}
339
340pub fn root_dir_point_segment_var<I: Span>(input: I) -> Res<I, PointSegVar> {
341 context("point:root_filesystem_segment", tag(":/"))(input)
342 .map(|(next, _)| (next, PointSegVar::FilesystemRootDir))
343}
344
345pub fn file_point_segment<I: Span>(input: I) -> Res<I, PointSeg> {
346 context("point:file_segment", file_chars)(input)
347 .map(|(next, filename)| (next, PointSeg::File(filename.to_string())))
348}
349
350pub fn point_var<I: Span>(input: I) -> Res<I, PointVar> {
351 context(
352 "point",
353 tuple((alt((root_point_var, point_non_root_var)), eop)),
354 )(input.clone())
355 .map(|(next, (point, _))| (next, point))
356}
357
358pub fn var_val<F, I: Span, O>(mut f: F) -> impl FnMut(I) -> Res<I, VarVal<O>> + Copy
393where
394 F: FnMut(I) -> Res<I, O> + Copy,
395{
396 move |input: I| context("var_val", alt((var, val(f))))(input)
397}
398
399fn val<I: Span, O, F>(f: F) -> impl FnMut(I) -> Res<I, VarVal<O>>
400where
401 F: FnMut(I) -> Res<I, O> + Copy,
402{
403 move |input| tw(f)(input).map(|(next, val)| (next, VarVal::Val(val)))
404}
405
406fn var<I: Span, O>(input: I) -> Res<I, VarVal<O>> {
407 tw(delimited(tag("${"), skewer_case, tag("}")))(input)
408 .map(|(next, var)| (next, VarVal::Var(var)))
409}
410
411pub fn var_seg<F, I: Span>(mut f: F) -> impl FnMut(I) -> Res<I, PointSegVar> + Copy
412where
413 F: Parser<I, PointSegCtx, ErrorTree<I>> + Copy,
414{
415 move |input: I| {
416 let offset = input.location_offset();
417 let result = pair(
418 peek(tag("$")),
419 context(
420 "var",
421 cut(delimited(tag("${"), skewer_case_chars, tag("}"))),
422 ),
423 )(input.clone());
424
425 match result {
426 Ok((next, (_, var))) => {
427 let range = Range {
428 start: offset,
429 end: next.location_offset(),
430 };
431 let trace = Trace {
432 range,
433 extra: next.extra(),
434 };
435 let var = Variable::new(var.to_string(), trace);
436 Ok((next, PointSegVar::Var(var)))
437 }
438 Err(err) => match err {
439 Err::Incomplete(needed) => return Err(nom::Err::Incomplete(needed)),
440 Err::Failure(err) => return Err(nom::Err::Failure(err)),
441 Err::Error(_) => f.parse(input).map(|(next, seg)| (next, seg.into())),
442 },
443 }
444 }
445}
446
447pub fn var_route<'a, F, I: Span>(mut f: F) -> impl FnMut(I) -> Res<I, RouteSegVar>
448where
449 F: Parser<I, RouteSeg, ErrorTree<I>>,
450{
451 move |input: I| {
452 let offset = input.location_offset();
453 let result = pair(
454 peek(tag("$")),
455 context(
456 "var",
457 cut(delimited(tag("${"), skewer_case_chars, tag("}"))),
458 ),
459 )(input.clone());
460 match result {
461 Ok((next, (_, var))) => {
462 let range = Range {
463 start: offset,
464 end: next.location_offset(),
465 };
466 let trace = Trace {
467 range,
468 extra: next.extra(),
469 };
470 let var = Variable::new(var.to_string(), trace);
471 Ok((next, RouteSegVar::Var(var)))
472 }
473 Err(err) => f.parse(input).map(|(next, seg)| (next, seg.into())),
474 }
475 }
476}
477pub fn root_point_var<I: Span>(input: I) -> Res<I, PointVar> {
478 context(
479 "root_point",
480 tuple((
481 opt(terminated(var_route(point_route_segment), tag("::"))),
482 tag("ROOT"),
483 )),
484 )(input)
485 .map(|(next, (route, _))| {
486 let route = route.unwrap_or(RouteSegVar::This);
487 let point = PointVar {
488 route,
489 segments: vec![],
490 };
491 (next, point)
492 })
493}
494
495pub fn point_non_root_var<I: Span>(input: I) -> Res<I, PointVar> {
496 context(
497 "point_non_root",
498 tuple((
499 context(
500 "point_route",
501 opt(terminated(var_route(point_route_segment), tag("::"))),
502 ),
503 var_seg(root_ctx_seg(space_point_segment)),
504 many0(base_seg(var_seg(pop(base_point_segment)))),
505 opt(base_seg(var_seg(pop(version_point_segment)))),
506 opt(tuple((
507 root_dir_point_segment_var,
508 many0(recognize(tuple((
509 var_seg(pop(dir_point_segment)),
510 tag("/"),
511 )))),
512 opt(var_seg(pop(file_point_segment))),
513 eop,
514 ))),
515 eop,
516 )),
517 )(input)
518 .map(
519 |(next, (route, space, mut bases, version, filesystem, _))| {
520 let route = route.unwrap_or(RouteSegVar::This);
521 let mut segments = vec![];
522 let mut bases: Vec<PointSegVar> = bases;
523 segments.push(space);
524 segments.append(&mut bases);
525 match version {
526 None => {}
527 Some(version) => {
528 segments.push(version);
529 }
530 }
531
532 if let Option::Some((fsroot, mut dirs, file, _)) = filesystem {
533 let mut dirs: Vec<PointSegVar> = dirs
534 .into_iter()
535 .map(|i| PointSegVar::Dir(i.to_string()))
536 .collect();
537 segments.push(fsroot);
538 segments.append(&mut dirs);
539 if let Some(file) = file {
540 segments.push(file);
541 }
542 }
543
544 let point = PointVar { route, segments };
545
546 (next, point)
547 },
548 )
549}
550
551pub fn consume_point(input: &str) -> Result<Point, SpaceErr> {
552 consume_point_ctx(input)?.collapse()
553}
554
555pub fn consume_point_ctx(input: &str) -> Result<PointCtx, SpaceErr> {
556 consume_point_var(input)?.collapse()
557}
558
559pub fn consume_point_var(input: &str) -> Result<PointVar, SpaceErr> {
560 let span = new_span(input);
561 let point = result(context("consume", all_consuming(point_var))(span))?;
562 Ok(point)
563}
564
565pub fn space_point_kind_segment<I: Span>(input: I) -> Res<I, PointKindSeg> {
654 tuple((space_point_segment, delim_kind))(input).map(|(next, (point_segment, kind))| {
655 (
656 next,
657 PointKindSeg {
658 segment: point_segment,
659 kind,
660 },
661 )
662 })
663}
664
665pub fn base_point_kind_segment<I: Span>(input: I) -> Res<I, PointKindSeg> {
666 tuple((base_point_segment, delim_kind))(input).map(|(next, (point_segment, kind))| {
667 (
668 next,
669 PointKindSeg {
670 segment: point_segment,
671 kind,
672 },
673 )
674 })
675}
676
677pub fn filepath_point_kind_segment<I: Span>(input: I) -> Res<I, PointKindSeg> {
678 alt((file_point_kind_segment, dir_point_kind_segment))(input)
679}
680pub fn dir_point_kind_segment<I: Span>(input: I) -> Res<I, PointKindSeg> {
681 tuple((dir_point_segment, delim_kind))(input).map(|(next, (point_segment, kind))| {
682 (
683 next,
684 PointKindSeg {
685 segment: point_segment,
686 kind,
687 },
688 )
689 })
690}
691
692pub fn file_point_kind_segment<I: Span>(input: I) -> Res<I, PointKindSeg> {
693 tuple((file_point_segment, delim_kind))(input).map(|(next, (point_segment, kind))| {
694 (
695 next,
696 PointKindSeg {
697 segment: point_segment,
698 kind,
699 },
700 )
701 })
702}
703
704pub fn version_point_kind_segment<I: Span>(input: I) -> Res<I, PointKindSeg> {
705 tuple((version_point_segment, delim_kind))(input).map(|(next, (point_segment, kind))| {
706 (
707 next,
708 PointKindSeg {
709 segment: point_segment,
710 kind,
711 },
712 )
713 })
714}
715
716pub fn consume_hierarchy<I: Span>(input: I) -> Result<PointHierarchy, SpaceErr> {
717 let (_, rtn) = all_consuming(point_kind_hierarchy)(input)?;
718 Ok(rtn)
719}
720
721pub fn point_kind_hierarchy<I: Span>(input: I) -> Res<I, PointHierarchy> {
722 tuple((
723 tuple((point_route_segment, space_point_kind_segment)),
724 many0(base_point_kind_segment),
725 opt(version_point_kind_segment),
726 many0(file_point_kind_segment),
727 ))(input)
728 .map(|(next, ((hub, space), mut bases, version, mut files))| {
729 let mut segments = vec![];
730 segments.push(space);
731 segments.append(&mut bases);
732 match version {
733 None => {}
734 Some(version) => {
735 segments.push(version);
736 }
737 }
738 segments.append(&mut files);
739
740 let point = PointHierarchy::new(hub, segments);
741
742 (next, point)
743 })
744}
745
746pub fn asterisk<T: Span, E: nom::error::ParseError<T>>(input: T) -> IResult<T, T, E>
747where
748 T: InputTakeAtPosition + nom::InputLength,
749 <T as InputTakeAtPosition>::Item: AsChar,
750{
751 input.split_at_position_complete(|item| item.as_char() != '*')
752}
753
754pub fn upper<T, E: nom::error::ParseError<T>>(input: T) -> IResult<T, T, E>
755where
756 T: InputTakeAtPosition + nom::InputLength,
757 <T as InputTakeAtPosition>::Item: AsChar,
758{
759 input.split_at_position_complete(|item| {
760 let char_item = item.as_char();
761
762 !char_item.is_uppercase()
763 })
764}
765
766pub fn in_double_quotes<T: Span>(i: T) -> Res<T, T>
787where
788 T: InputTakeAtPosition + nom::InputLength,
789 <T as InputTakeAtPosition>::Item: AsChar,
790{
791 i.split_at_position1_complete(
792 |item| {
793 let char_item = item.as_char();
794 char_item == '\"'
795 },
796 ErrorKind::AlphaNumeric,
797 )
798}
799
800pub fn skewer_colon<T: Span>(i: T) -> Res<T, T>
801where
802 T: InputTakeAtPosition + nom::InputLength,
803 <T as InputTakeAtPosition>::Item: AsChar,
804{
805 i.split_at_position1_complete(
806 |item| {
807 let char_item = item.as_char();
808 !(char_item == '-')
809 && !(char_item == ':')
810 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
811 },
812 ErrorKind::AlphaNumeric,
813 )
814}
815
816pub fn skewer_dot<I: Span, E>(i: I) -> IResult<I, I, E>
817where
818 I: InputTakeAtPosition + nom::InputLength,
819 <I as InputTakeAtPosition>::Item: AsChar,
820 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
821{
822 i.split_at_position1_complete(
823 |item| {
824 let char_item = item.as_char();
825 !(char_item == '-')
826 && !(char_item == '.')
827 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
828 },
829 ErrorKind::AlphaNumeric,
830 )
831}
832
833pub fn domain<I: Span>(i: I) -> Res<I, Domain> {
834 domain_chars(i).map(|(next, domain)| {
835 (
836 next,
837 Domain {
838 string: domain.to_string(),
839 },
840 )
841 })
842}
843
844pub fn point_segment_chars<T: Span>(i: T) -> Res<T, T>
845where
846 T: InputTakeAtPosition + nom::InputLength,
847 <T as InputTakeAtPosition>::Item: AsChar,
848{
849 i.split_at_position1_complete(
850 |item| {
851 let char_item = item.as_char();
852 !(char_item == '-')
853 && !(char_item == '.')
854 && !(char_item.is_alpha() || char_item.is_dec_digit())
855 },
856 ErrorKind::AlphaNumeric,
857 )
858}
859
860pub fn version_chars<T: Span>(i: T) -> Res<T, T>
861where
862 T: InputTakeAtPosition + nom::InputLength,
863 <T as InputTakeAtPosition>::Item: AsChar,
864{
865 i.split_at_position1_complete(
866 |item| {
867 let char_item = item.as_char();
868 char_item != '.'
869 && char_item != '-'
870 && !char_item.is_digit(10)
871 && !(char_item.is_alpha() && char_item.is_lowercase())
872 },
873 ErrorKind::AlphaNumeric,
874 )
875}
876
877pub fn version_req_chars<T: Span>(i: T) -> Res<T, T>
878where
879 T: InputTakeAtPosition + nom::InputLength,
880 <T as InputTakeAtPosition>::Item: AsChar,
881{
882 i.split_at_position1_complete(
883 |item| {
884 let char_item = item.as_char();
885 !(char_item == '-')
886 && !(char_item == '>')
887 && !(char_item == '<')
888 && !(char_item == '^')
889 && !(char_item == '=')
890 && !(char_item == '.')
891 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
892 },
893 ErrorKind::AlphaNumeric,
894 )
895}
896
897pub fn lowercase1<T: Span>(i: T) -> Res<T, T>
898where
899 T: InputTakeAtPosition + nom::InputLength,
900 <T as InputTakeAtPosition>::Item: AsChar,
901{
902 i.split_at_position1_complete(
903 |item| {
904 let char_item = item.as_char();
905 !(char_item.is_alpha() && char_item.is_lowercase())
906 },
907 ErrorKind::AlphaNumeric,
908 )
909}
910
911pub fn rec_skewer<I: Span>(input: I) -> Res<I, I> {
912 recognize(tuple((lowercase1, opt(skewer))))(input)
913}
914
915pub fn rec_skewer_capture<I: Span>(input: I) -> Res<I, I> {
916 recognize(tuple((lowercase1, opt(skewer_chars_plus_capture))))(input)
917}
918
919pub fn camel_chars<T>(i: T) -> Res<T, T>
920where
921 T: InputTakeAtPosition + nom::InputLength + Clone + Offset + Slice<RangeTo<usize>>,
922 <T as InputTakeAtPosition>::Item: AsChar,
923{
924 recognize(pair(upper, alphanumeric0))(i)
925}
926
927pub fn skewer_chars<T: Span>(i: T) -> Res<T, T>
928where
929 T: InputTakeAtPosition + nom::InputLength,
930 <T as InputTakeAtPosition>::Item: AsChar,
931{
932 i.split_at_position1_complete(
933 |item| {
934 let char_item = item.as_char();
935 char_item != '-'
936 && !char_item.is_digit(10)
937 && !(char_item.is_alpha() && char_item.is_lowercase())
938 },
939 ErrorKind::AlphaNumeric,
940 )
941}
942
943pub fn parse_uuid<I: Span>(i: I) -> Res<I, Uuid> {
944 let (next, uuid) = uuid_chars(i.clone())?;
945 Ok((
946 next,
947 Uuid::from(uuid)
948 .map_err(|e| nom::Err::Error(ErrorTree::from_error_kind(i, ErrorKind::Tag)))?,
949 ))
950}
951
952pub fn uuid_chars<T: Span>(i: T) -> Res<T, T>
953where
954 T: InputTakeAtPosition + nom::InputLength,
955 <T as InputTakeAtPosition>::Item: AsChar,
956{
957 skewer_chars(i)
959}
960
961pub fn skewer_chars_plus_capture<T: Span>(i: T) -> Res<T, T>
962where
963 T: InputTakeAtPosition + nom::InputLength,
964 <T as InputTakeAtPosition>::Item: AsChar,
965{
966 i.split_at_position1_complete(
967 |item| {
968 let char_item = item.as_char();
969 char_item != '-'
970 && char_item != '$'
971 && !char_item.is_digit(10)
972 && !(char_item.is_alpha() && char_item.is_lowercase())
973 },
974 ErrorKind::AlphaNumeric,
975 )
976}
977
978pub fn skewer_chars_template<T: Span>(i: T) -> Res<T, T>
979where
980 T: InputTakeAtPosition + nom::InputLength,
981 <T as InputTakeAtPosition>::Item: AsChar,
982{
983 i.split_at_position1_complete(
984 |item| {
985 let char_item = item.as_char();
986 char_item != '-'
987 && char_item.as_char() != '%'
988 && !char_item.is_digit(10)
989 && !(char_item.is_alpha() && char_item.is_lowercase())
990 },
991 ErrorKind::AlphaNumeric,
992 )
993}
994
995pub fn space_chars<T: Span>(i: T) -> Res<T, T>
996where
997 T: InputTakeAtPosition + nom::InputLength,
998 <T as InputTakeAtPosition>::Item: AsChar,
999{
1000 i.split_at_position1_complete(
1001 |item| {
1002 let char_item = item.as_char();
1003 !(char_item == '-')
1004 && !(char_item == '.')
1005 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
1006 },
1007 ErrorKind::AlphaNumeric,
1008 )
1009}
1010
1011pub fn space_chars_plus_capture<T: Span>(i: T) -> Res<T, T>
1012where
1013 T: InputTakeAtPosition + nom::InputLength,
1014 <T as InputTakeAtPosition>::Item: AsChar,
1015{
1016 i.split_at_position1_complete(
1017 |item| {
1018 let char_item = item.as_char();
1019 !(char_item == '-')
1020 && !(char_item == '.')
1021 && !(char_item == '$')
1022 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
1023 },
1024 ErrorKind::AlphaNumeric,
1025 )
1026}
1027
1028pub fn domain_chars<T: Span>(i: T) -> Res<T, T>
1029where
1030 T: InputTakeAtPosition + nom::InputLength,
1031 <T as InputTakeAtPosition>::Item: AsChar,
1032{
1033 i.split_at_position1_complete(
1034 |item| {
1035 let char_item = item.as_char();
1036 !(char_item == '-')
1037 && !(char_item == '.')
1038 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
1039 },
1040 ErrorKind::AlphaNumeric,
1041 )
1042}
1043
1044pub fn path_regex<I: Span>(input: I) -> Res<I, I> {
1045 let (next, regex_span) = context("regex", recognize(pair(tag("/"), nospace0)))(input.clone())?;
1046
1047 let regex_string = regex_span.to_string();
1048 match Regex::new(regex_string.as_str()) {
1049 Ok(regex) => Ok((next, regex_span)),
1050 Err(err) => {
1051 println!("regex error {}", err.to_string());
1052 return Err(nom::Err::Error(ErrorTree::from_error_kind(
1053 input,
1054 ErrorKind::Tag,
1055 )));
1056 }
1057 }
1058}
1059
1060pub fn regex<T: Span>(i: T) -> Res<T, T>
1061where
1062 T: InputTakeAtPosition + nom::InputLength,
1063 <T as InputTakeAtPosition>::Item: AsChar,
1064{
1065 i.split_at_position1_complete(
1066 |item| {
1067 let char_item = item.as_char();
1068 !(char_item == '-')
1069 && !(char_item == '.')
1070 && !(char_item == '/')
1071 && !(char_item == ':')
1072 && !(char_item == '_')
1073 && !(char_item.is_alpha() || char_item.is_dec_digit())
1074 },
1075 ErrorKind::AlphaNumeric,
1076 )
1077}
1078
1079pub fn filepath_chars<T: Span>(i: T) -> Res<T, T>
1080where
1081 T: InputTakeAtPosition + nom::InputLength,
1082 <T as InputTakeAtPosition>::Item: AsChar,
1083{
1084 i.split_at_position1_complete(
1085 |item| {
1086 let char_item = item.as_char();
1087 !(char_item == '-')
1088 && !(char_item == '.')
1089 && !(char_item == '/')
1090 && !(char_item == ':')
1091 && !(char_item == '_')
1092 && !(char_item.is_alpha() || char_item.is_dec_digit())
1093 },
1094 ErrorKind::AlphaNumeric,
1095 )
1096}
1097
1098pub fn file_chars_plus_capture<T: Span>(i: T) -> Res<T, T>
1099where
1100 T: InputTakeAtPosition + nom::InputLength,
1101 <T as InputTakeAtPosition>::Item: AsChar,
1102{
1103 i.split_at_position1_complete(
1104 |item| {
1105 let char_item = item.as_char();
1106 !(char_item == '-')
1107 && !(char_item == '.')
1108 && !(char_item == '_')
1109 && !(char_item == '$')
1110 && !(char_item.is_alpha() || char_item.is_dec_digit())
1111 },
1112 ErrorKind::AlphaNumeric,
1113 )
1114}
1115
1116pub fn file_chars<T: Span>(i: T) -> Res<T, T>
1117where
1118 T: InputTakeAtPosition + nom::InputLength,
1119 <T as InputTakeAtPosition>::Item: AsChar,
1120{
1121 i.split_at_position1_complete(
1122 |item| {
1123 let char_item = item.as_char();
1124 !(char_item == '-')
1125 && !(char_item == '.')
1126 && !(char_item == '_')
1127 && !(char_item.is_alpha() || char_item.is_dec_digit())
1128 },
1129 ErrorKind::AlphaNumeric,
1130 )
1131}
1132
1133pub fn file_chars_template<T: Span>(i: T) -> Res<T, T>
1134where
1135 T: InputTakeAtPosition + nom::InputLength,
1136 <T as InputTakeAtPosition>::Item: AsChar,
1137{
1138 i.split_at_position1_complete(
1139 |item| {
1140 let char_item = item.as_char();
1141 !(char_item == '-')
1142 && !(char_item == '.')
1143 && !(char_item == '_')
1144 && !(char_item == '%')
1145 && !(char_item.is_alpha() || char_item.is_dec_digit())
1146 },
1147 ErrorKind::AlphaNumeric,
1148 )
1149}
1150
1151pub fn not_space<I: Span>(input: I) -> Res<I, I> {
1152 is_not(" \n\r\t")(input)
1153}
1154
1155pub fn path<I: Span>(input: I) -> Res<I, I> {
1156 recognize(tuple((tag("/"), opt(filepath_chars))))(input)
1157}
1158
1159pub fn subst_path<I: Span>(input: I) -> Res<I, Subst<I>> {
1160 pair(peek(tag("/")), subst(filepath_chars))(input).map(|(next, (_, path))| (next, path))
1161}
1162
1163pub fn consume_path<I: Span>(input: I) -> Res<I, I> {
1164 all_consuming(path)(input)
1165}
1166
1167#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1168pub struct CamelCase {
1169 string: String,
1170}
1171
1172impl CamelCase {
1173 pub fn as_str(&self) -> &str {
1174 self.string.as_str()
1175 }
1176}
1177
1178impl FromStr for CamelCase {
1179 type Err = SpaceErr;
1180
1181 fn from_str(s: &str) -> Result<Self, Self::Err> {
1182 result(all_consuming(camel_case)(new_span(s)))
1183 }
1184}
1185
1186impl Serialize for CamelCase {
1187 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1188 where
1189 S: Serializer,
1190 {
1191 serializer.serialize_str(self.string.as_str())
1192 }
1193}
1194
1195impl<'de> Deserialize<'de> for CamelCase {
1196 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1197 where
1198 D: Deserializer<'de>,
1199 {
1200 let string = String::deserialize(deserializer)?;
1201
1202 let result = result(camel_case(new_span(string.as_str())));
1203 match result {
1204 Ok(camel) => Ok(camel),
1205 Err(err) => Err(serde::de::Error::custom(err.to_string().as_str())),
1206 }
1207 }
1208}
1209
1210impl Display for CamelCase {
1211 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1212 f.write_str(self.string.as_str())
1213 }
1214}
1215
1216impl Deref for CamelCase {
1217 type Target = String;
1218
1219 fn deref(&self) -> &Self::Target {
1220 &self.string
1221 }
1222}
1223
1224#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1225pub struct Domain {
1226 string: String,
1227}
1228
1229impl Serialize for Domain {
1230 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1231 where
1232 S: Serializer,
1233 {
1234 serializer.serialize_str(self.string.as_str())
1235 }
1236}
1237
1238impl<'de> Deserialize<'de> for Domain {
1239 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1240 where
1241 D: Deserializer<'de>,
1242 {
1243 let string = String::deserialize(deserializer)?;
1244
1245 let result = result(domain(new_span(string.as_str())));
1246 match result {
1247 Ok(domain) => Ok(domain),
1248 Err(err) => Err(serde::de::Error::custom(err.to_string())),
1249 }
1250 }
1251}
1252
1253impl FromStr for Domain {
1254 type Err = SpaceErr;
1255
1256 fn from_str(s: &str) -> Result<Self, Self::Err> {
1257 result(all_consuming(domain)(new_span(s)))
1258 }
1259}
1260
1261impl Display for Domain {
1262 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1263 f.write_str(self.string.as_str())
1264 }
1265}
1266
1267impl Deref for Domain {
1268 type Target = String;
1269
1270 fn deref(&self) -> &Self::Target {
1271 &self.string
1272 }
1273}
1274
1275#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1276pub struct SkewerCase {
1277 string: String,
1278}
1279
1280impl Serialize for SkewerCase {
1281 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1282 where
1283 S: Serializer,
1284 {
1285 serializer.serialize_str(self.string.as_str())
1286 }
1287}
1288
1289impl<'de> Deserialize<'de> for SkewerCase {
1290 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1291 where
1292 D: Deserializer<'de>,
1293 {
1294 let string = String::deserialize(deserializer)?;
1295
1296 let result = result(skewer_case(new_span(string.as_str())));
1297 match result {
1298 Ok(skewer) => Ok(skewer),
1299 Err(err) => Err(serde::de::Error::custom(err.to_string())),
1300 }
1301 }
1302}
1303
1304impl FromStr for SkewerCase {
1305 type Err = SpaceErr;
1306
1307 fn from_str(s: &str) -> Result<Self, Self::Err> {
1308 result(all_consuming(skewer_case)(new_span(s)))
1309 }
1310}
1311
1312impl Display for SkewerCase {
1313 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1314 f.write_str(self.string.as_str())
1315 }
1316}
1317
1318impl Deref for SkewerCase {
1319 type Target = String;
1320
1321 fn deref(&self) -> &Self::Target {
1322 &self.string
1323 }
1324}
1325
1326pub fn camel_case<I: Span>(input: I) -> Res<I, CamelCase> {
1327 context("expect-camel-case", camel_case_chars)(input).map(|(next, camel_case_chars)| {
1328 (
1329 next,
1330 CamelCase {
1331 string: camel_case_chars.to_string(),
1332 },
1333 )
1334 })
1335}
1336
1337pub fn skewer_case<I: Span>(input: I) -> Res<I, SkewerCase> {
1338 context("expect-skewer-case", skewer_case_chars)(input).map(|(next, skewer_case_chars)| {
1339 (
1340 next,
1341 SkewerCase {
1342 string: skewer_case_chars.to_string(),
1343 },
1344 )
1345 })
1346}
1347
1348pub fn camel_case_chars<I: Span>(input: I) -> Res<I, I> {
1349 recognize(tuple((is_a("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), alphanumeric0)))(input)
1350}
1351
1352pub fn skewer_case_chars<I: Span>(input: I) -> Res<I, I> {
1353 recognize(tuple((
1354 is_a("abcdefghijklmnopqrstuvwxyz"),
1355 many0(alt((alphanumeric1, tag("-")))),
1356 )))(input)
1357}
1358
1359pub fn lowercase_alphanumeric<I: Span>(input: I) -> Res<I, I> {
1360 recognize(tuple((lowercase1, alphanumeric0)))(input)
1361}
1362
1363pub fn single_lowercase<T: Span, Input, Error: ParseError<Input>>(
1364 arr: T,
1365) -> impl Fn(Input) -> IResult<Input, Input, Error>
1366where
1367 Input: InputTakeAtPosition,
1368 T: FindToken<<Input as InputTakeAtPosition>::Item>,
1369{
1370 move |i: Input| {
1371 let e: ErrorKind = ErrorKind::IsA;
1372 i.split_at_position1_complete(|c| !arr.find_token(c), e)
1373 }
1374}
1375
1376pub fn single_lowerscase<I: Span>(input: I) -> Res<I, I> {
1377 is_a("abcdefghijklmnopqrstuvwxyz")(input)
1378}
1379pub fn single_digit<I: Span>(input: I) -> Res<I, I> {
1380 is_a("abcdefghijklmnopqrstuvwxyz")(input)
1381}
1382
1383pub fn camel_case_to_string_matcher<I: Span>(input: I) -> Res<I, StringMatcher> {
1384 camel_case_chars(input).map(|(next, camel)| (next, StringMatcher::new(camel.to_string())))
1385}
1386
1387fn parse_version_major_minor_patch<I: Span>(input: I) -> Res<I, (I, I, I)> {
1388 context(
1389 "version_major_minor_patch",
1390 tuple((
1391 terminated(digit1, tag(".")),
1392 terminated(digit1, tag(".")),
1393 terminated(digit1, not(digit1)),
1394 )),
1395 )(input)
1396}
1397
1398pub fn parse_version<I: Span>(input: I) -> Res<I, ((I, I, I), Option<I>)> {
1399 tuple((
1400 parse_version_major_minor_patch,
1401 opt(preceded(tag("-"), skewer_chars)),
1402 ))(input)
1403}
1404
1405pub fn rec_version<I: Span>(input: I) -> Res<I, I> {
1406 recognize(parse_version)(input)
1407}
1408
1409pub fn base_point_segment_wildcard<I: Span>(input: I) -> Res<I, PointTemplateSeg> {
1410 preceded(
1411 tag(":"),
1412 recognize(tuple((many0(skewer), tag("%"), many0(skewer)))),
1413 )(input)
1414 .map(|(next, base)| (next, PointTemplateSeg::Wildcard(base.to_string())))
1415}
1416
1417pub fn base_point_segment_template<I: Span>(input: I) -> Res<I, PointTemplateSeg> {
1418 preceded(tag(":"), rec_skewer)(input).map(|(next, base)| {
1419 (
1420 next,
1421 PointTemplateSeg::ExactSeg(PointSeg::Base(base.to_string())),
1422 )
1423 })
1424}
1425
1426pub fn filepath_point_segment_wildcard<I: Span>(input: I) -> Res<I, PointTemplateSeg> {
1427 recognize(tuple((
1428 many0(filepath_chars),
1429 tag("%"),
1430 many0(filepath_chars),
1431 )))(input)
1432 .map(|(next, base)| (next, PointTemplateSeg::Wildcard(base.to_string())))
1433}
1434
1435pub fn filepath_point_segment_template<I: Span>(input: I) -> Res<I, PointTemplateSeg> {
1436 filesystem_point_segment(input)
1437 .map(|(next, segment)| (next, PointTemplateSeg::ExactSeg(segment)))
1438}
1439
1440pub fn point_template<I: Span>(input: I) -> Res<I, PointTemplateVar> {
1573 let (next, (point, wildcard)) = pair(point_var, opt(recognize(tag("%"))))(input.clone())?;
1574
1575 if point.is_root() {
1576 return Ok((
1577 next,
1578 PointTemplateVar {
1579 parent: point,
1580 child_segment_template: PointSegTemplate::Root,
1581 },
1582 ));
1583 }
1584
1585 let parent = point
1586 .parent()
1587 .expect("expect that point template has a parent");
1588 let child = point
1589 .last_segment()
1590 .expect("expect that point template has a last segment");
1591
1592 match wildcard {
1593 None => Ok((
1594 next,
1595 PointTemplateVar {
1596 parent,
1597 child_segment_template: PointSegTemplate::Exact(child.to_string()),
1598 },
1599 )),
1600 Some(_) => {
1601 let child = format!("{}%", child.to_string());
1602 Ok((
1603 next,
1604 PointTemplateVar {
1605 parent,
1606 child_segment_template: PointSegTemplate::Exact(child),
1607 },
1608 ))
1609 }
1610 }
1611}
1612
1613pub fn kind_template<I: Span>(input: I) -> Res<I, KindTemplate> {
1614 tuple((
1615 kind_base,
1616 opt(delimited(
1617 tag("<"),
1618 tuple((
1619 camel_case,
1620 opt(delimited(tag("<"), specific_selector, tag(">"))),
1621 )),
1622 tag(">"),
1623 )),
1624 ))(input)
1625 .map(|(next, (kind, more))| {
1626 let mut parts = KindTemplate {
1627 base: kind,
1628 sub: None,
1629 specific: None,
1630 };
1631
1632 match more {
1633 Some((sub, specific)) => {
1634 parts.sub = Option::Some(sub);
1635 parts.specific = specific;
1636 }
1637 None => {}
1638 }
1639
1640 (next, parts)
1641 })
1642}
1643
1644pub fn template<I: Span>(input: I) -> Res<I, TemplateVar> {
1645 tuple((point_template, delimited(tag("<"), kind_template, tag(">"))))(input)
1646 .map(|(next, (point, kind))| (next, TemplateVar { point, kind }))
1647}
1648
1649pub fn set_property_mod<I: Span>(input: I) -> Res<I, PropertyMod> {
1650 tuple((tag("+"), skewer_dot, tag("="), property_value))(input).map(
1651 |(next, (_, key, _, value))| {
1652 (
1653 next,
1654 PropertyMod::Set {
1655 key: key.to_string(),
1656 value: value.to_string(),
1657 lock: false,
1658 },
1659 )
1660 },
1661 )
1662}
1663
1664pub fn set_property_mod_lock<I: Span>(input: I) -> Res<I, PropertyMod> {
1665 tuple((tag("+@"), skewer_dot, tag("="), property_value))(input).map(
1666 |(next, (_, key, _, value))| {
1667 (
1668 next,
1669 PropertyMod::Set {
1670 key: key.to_string(),
1671 value: value.to_string(),
1672 lock: true,
1673 },
1674 )
1675 },
1676 )
1677}
1678
1679pub fn property_value_not_space_or_comma<I: Span>(input: I) -> Res<I, I> {
1680 is_not(" \n\r\t,")(input)
1681}
1682
1683pub fn property_value_single_quotes<I: Span>(input: I) -> Res<I, I> {
1684 delimited(tag("'"), is_not("'"), tag("'"))(input)
1685}
1686
1687pub fn property_value_double_quotes<I: Span>(input: I) -> Res<I, I> {
1688 delimited(tag("\""), is_not("\""), tag("\""))(input)
1689}
1690
1691pub fn property_value<I: Span>(input: I) -> Res<I, I> {
1692 alt((
1693 property_value_single_quotes,
1694 property_value_double_quotes,
1695 property_value_not_space_or_comma,
1696 ))(input)
1697}
1698
1699pub fn unset_property_mod<I: Span>(input: I) -> Res<I, PropertyMod> {
1700 tuple((tag("!"), skewer_dot))(input)
1701 .map(|(next, (_, name))| (next, PropertyMod::UnSet(name.to_string())))
1702}
1703
1704pub fn property_mod<I: Span>(input: I) -> Res<I, PropertyMod> {
1705 alt((set_property_mod, unset_property_mod))(input)
1706}
1707
1708pub fn set_properties<I: Span>(input: I) -> Res<I, SetProperties> {
1709 separated_list0(tag(","), tuple((multispace0, property_mod, multispace0)))(input).map(
1710 |(next, properties)| {
1711 let mut set_properties = SetProperties::new();
1712 for (_, property, _) in properties {
1713 set_properties.push(property);
1714 }
1715 (next, set_properties)
1716 },
1717 )
1718}
1719
1720pub fn get_properties<I: Span>(input: I) -> Res<I, Vec<String>> {
1721 separated_list0(tag(","), tuple((multispace0, skewer, multispace0)))(input).map(
1722 |(next, keys)| {
1723 let keys: Vec<String> = keys.iter().map(|(_, key, _)| key.to_string()).collect();
1724 (next, keys)
1725 },
1726 )
1727}
1728
1729pub fn create<I: Span>(input: I) -> Res<I, CreateVar> {
1730 tuple((
1731 opt(alt((
1732 value(Strategy::Override, tag("!")),
1733 value(Strategy::Ensure, tag("?")),
1734 ))),
1735 space1,
1736 template,
1737 opt(delimited(tag("{"), set_properties, tag("}"))),
1738 ))(input)
1739 .map(|(next, (strategy, _, template, properties))| {
1740 let strategy = match strategy {
1741 None => Strategy::Commit,
1742 Some(strategy) => strategy,
1743 };
1744 let properties = match properties {
1745 Some(properties) => properties,
1746 None => SetProperties::new(),
1747 };
1748 let create = CreateVar {
1749 template,
1750 state: StateSrcVar::None,
1751 properties,
1752 strategy,
1753 };
1754 (next, create)
1755 })
1756}
1757
1758pub fn set<I: Span>(input: I) -> Res<I, SetVar> {
1759 tuple((point_var, delimited(tag("{"), set_properties, tag("}"))))(input).map(
1760 |(next, (point, properties))| {
1761 let set = SetVar { point, properties };
1762 (next, set)
1763 },
1764 )
1765}
1766
1767pub fn get<I: Span>(input: I) -> Res<I, GetVar> {
1768 tuple((
1769 point_var,
1770 opt(delimited(tag("{"), get_properties, tag("}"))),
1771 ))(input)
1772 .map(|(next, (point, keys))| {
1773 let op = match keys {
1774 None => GetOp::State,
1775 Some(keys) => GetOp::Properties(keys),
1776 };
1777 let get = GetVar { point, op };
1778
1779 (next, get)
1780 })
1781}
1782
1783pub fn select<I: Span>(input: I) -> Res<I, SelectVar> {
1784 point_selector(input).map(|(next, point_kind_pattern)| {
1785 let select = SelectVar {
1786 pattern: point_kind_pattern,
1787 properties: Default::default(),
1788 into_substance: SelectIntoSubstance::Stubs,
1789 kind: SelectKind::Initial,
1790 };
1791 (next, select)
1792 })
1793}
1794
1795pub fn publish<I: Span>(input: I) -> Res<I, CreateVar> {
1796 let (next, (upload, _, point)) = tuple((upload_block, space1, point_template))(input.clone())?;
1797
1798 let template = TemplateVar {
1821 point,
1822 kind: KindTemplate {
1823 base: BaseKind::Bundle,
1824 sub: None,
1825 specific: None,
1826 },
1827 };
1828
1829 let create = CreateVar {
1830 template,
1831 state: StateSrcVar::None,
1832 properties: Default::default(),
1833 strategy: Strategy::Commit,
1834 };
1835
1836 Ok((next, create))
1837}
1838
1839#[derive(Debug, Clone, Serialize, Deserialize)]
1840pub enum Ctx {
1841 WorkingPoint,
1842 PointFromRoot,
1843}
1844
1845impl ToString for Ctx {
1846 fn to_string(&self) -> String {
1847 match self {
1848 Ctx::WorkingPoint => ".".to_string(),
1849 Ctx::PointFromRoot => "...".to_string(),
1850 }
1851 }
1852}
1853
1854#[derive(Clone, Serialize, Deserialize)]
1855pub struct File {
1856 pub name: String,
1857 pub content: Bin,
1858}
1859
1860impl File {
1861 pub fn new<S: ToString>(name: S, content: Bin) -> Self {
1862 Self {
1863 name: name.to_string(),
1864 content,
1865 }
1866 }
1867}
1868
1869#[derive(Clone, Serialize, Deserialize)]
1870pub struct FileResolver {
1871 pub files: HashMap<String, Bin>,
1872}
1873
1874impl FileResolver {
1875 pub fn new() -> Self {
1876 Self {
1877 files: HashMap::new(),
1878 }
1879 }
1880
1881 pub fn file<N: ToString>(&self, name: N) -> Result<File, ResolverErr> {
1882 if let Some(content) = self.files.get(&name.to_string()) {
1883 Ok(File::new(name, content.clone()))
1884 } else {
1885 Err(ResolverErr::NotFound)
1886 }
1887 }
1888
1889 pub fn singleton(&self) -> Result<File, ResolverErr> {
1891 if self.files.len() == 1 {
1892 let i = &mut self.files.iter();
1893 if let Some((name, content)) = i.next() {
1894 Ok(File::new(name.clone(), content.clone()))
1895 } else {
1896 Err(ResolverErr::NotFound)
1897 }
1898 } else {
1899 Err(ResolverErr::NotFound)
1900 }
1901 }
1902}
1903
1904#[derive(Clone, Serialize, Deserialize)]
1905pub struct Env {
1906 parent: Option<Box<Env>>,
1907 pub point: Point,
1908 pub vars: HashMap<String, Substance>,
1909 pub file_resolver: FileResolver,
1910
1911 #[serde(skip_serializing)]
1912 #[serde(skip_deserializing)]
1913 #[serde(default)]
1914 pub var_resolvers: MultiVarResolver,
1915}
1916
1917impl Env {
1918 pub fn new(working: Point) -> Self {
1919 Self {
1920 parent: None,
1921 point: working,
1922 vars: HashMap::new(),
1923 file_resolver: FileResolver::new(),
1924 var_resolvers: MultiVarResolver::new(),
1925 }
1926 }
1927
1928 pub fn no_point() -> Self {
1929 Self::new(Point::root())
1930 }
1931
1932 pub fn push(self) -> Self {
1933 Self {
1934 point: self.point.clone(),
1935 parent: Some(Box::new(self)),
1936 vars: HashMap::new(),
1937 file_resolver: FileResolver::new(),
1938 var_resolvers: MultiVarResolver::new(),
1939 }
1940 }
1941
1942 pub fn push_working<S: ToString>(self, segs: S) -> Result<Self, SpaceErr> {
1943 Ok(Self {
1944 point: self.point.push(segs.to_string())?,
1945 parent: Some(Box::new(self)),
1946 vars: HashMap::new(),
1947 file_resolver: FileResolver::new(),
1948 var_resolvers: MultiVarResolver::new(),
1949 })
1950 }
1951
1952 pub fn point_or(&self) -> Result<Point, SpaceErr> {
1953 Ok(self.point.clone())
1954 }
1955
1956 pub fn pop(self) -> Result<Env, SpaceErr> {
1957 Ok(*self
1958 .parent
1959 .ok_or::<SpaceErr>("expected parent scopedVars".into())?)
1960 }
1961
1962 pub fn add_var_resolver(&mut self, var_resolver: Arc<dyn VarResolver>) {
1963 self.var_resolvers.push(var_resolver);
1964 }
1965
1966 pub fn val<K: ToString>(&self, var: K) -> Result<Substance, ResolverErr> {
1967 match self.vars.get(&var.to_string()) {
1968 None => {
1969 if let Ok(val) = self.var_resolvers.val(var.to_string().as_str()) {
1970 Ok(val.clone())
1971 } else if let Some(parent) = self.parent.as_ref() {
1972 parent.val(var.to_string())
1973 } else {
1974 Err(ResolverErr::NotFound)
1975 }
1976 }
1977 Some(val) => Ok(val.clone()),
1978 }
1979 }
1980
1981 pub fn set_working(&mut self, point: Point) {
1982 self.point = point;
1983 }
1984
1985 pub fn working(&self) -> &Point {
1986 &self.point
1987 }
1988
1989 pub fn set_var_str<V: ToString>(&mut self, key: V, value: V) {
1990 self.vars
1991 .insert(key.to_string(), Substance::Text(value.to_string()));
1992 }
1993
1994 pub fn set_var<V: ToString>(&mut self, key: V, value: Substance) {
1995 self.vars.insert(key.to_string(), value);
1996 }
1997
1998 pub fn file<N: ToString>(&self, name: N) -> Result<File, ResolverErr> {
1999 match self.file_resolver.files.get(&name.to_string()) {
2000 None => {
2001 if let Some(parent) = self.parent.as_ref() {
2002 parent.file(name.to_string())
2003 } else {
2004 Err(ResolverErr::NotFound)
2005 }
2006 }
2007 Some(bin) => Ok(File::new(name.to_string(), bin.clone())),
2008 }
2009 }
2010
2011 pub fn set_file<N: ToString>(&mut self, name: N, content: Bin) {
2012 self.file_resolver.files.insert(name.to_string(), content);
2013 }
2014}
2015
2016impl Default for Env {
2017 fn default() -> Self {
2018 Self {
2019 parent: None,
2020 point: Point::root(),
2021 vars: HashMap::new(),
2022 file_resolver: FileResolver::new(),
2023 var_resolvers: MultiVarResolver::new(),
2024 }
2025 }
2026}
2027
2028#[derive(Clone)]
2130pub struct CompositeResolver {
2131 pub env_resolver: Arc<dyn VarResolver>,
2132 pub scope_resolver: MapResolver,
2133 pub other_resolver: MultiVarResolver,
2134}
2135
2136impl CompositeResolver {
2137 pub fn new() -> Self {
2138 Self {
2139 env_resolver: Arc::new(NoResolver::new()),
2140 scope_resolver: MapResolver::new(),
2141 other_resolver: MultiVarResolver::new(),
2142 }
2143 }
2144
2145 pub fn set<S>(&mut self, key: S, value: Substance)
2146 where
2147 S: ToString,
2148 {
2149 self.scope_resolver.insert(key.to_string(), value);
2150 }
2151}
2152
2153impl VarResolver for CompositeResolver {
2154 fn val(&self, var: &str) -> Result<Substance, ResolverErr> {
2155 if let Ok(val) = self.scope_resolver.val(var) {
2156 Ok(val)
2157 } else if let Ok(val) = self.scope_resolver.val(var) {
2158 Ok(val)
2159 } else if let Ok(val) = self.other_resolver.val(var) {
2160 Ok(val)
2161 } else {
2162 Err(ResolverErr::NotFound)
2163 }
2164 }
2165}
2166
2167pub trait CtxResolver {
2168 fn working_point(&self) -> Result<&Point, SpaceErr>;
2169}
2170
2171pub struct PointCtxResolver(Point);
2172
2173impl CtxResolver for PointCtxResolver {
2174 fn working_point(&self) -> Result<&Point, SpaceErr> {
2175 Ok(&self.0)
2176 }
2177}
2178
2179pub enum ResolverErr {
2180 NotAvailable,
2181 NotFound,
2182}
2183
2184pub trait VarResolver: Send + Sync {
2185 fn val(&self, var: &str) -> Result<Substance, ResolverErr> {
2186 Err(ResolverErr::NotFound)
2187 }
2188}
2189
2190#[derive(Clone)]
2191pub struct NoResolver;
2192
2193impl NoResolver {
2194 pub fn new() -> Self {
2195 Self {}
2196 }
2197}
2198
2199impl VarResolver for NoResolver {}
2200
2201#[derive(Clone)]
2202pub struct MapResolver {
2203 pub map: HashMap<String, Substance>,
2204}
2205
2206impl MapResolver {
2207 pub fn new() -> Self {
2208 Self {
2209 map: HashMap::new(),
2210 }
2211 }
2212
2213 pub fn insert<K: ToString>(&mut self, key: K, value: Substance) {
2214 self.map.insert(key.to_string(), value);
2215 }
2216}
2217
2218impl VarResolver for MapResolver {
2219 fn val(&self, var: &str) -> Result<Substance, ResolverErr> {
2220 self.map
2221 .get(&var.to_string())
2222 .cloned()
2223 .ok_or(ResolverErr::NotFound)
2224 }
2225}
2226
2227#[derive(Clone)]
2228pub struct RegexCapturesResolver {
2229 regex: Regex,
2230 text: String,
2231}
2232
2233impl RegexCapturesResolver {
2234 pub fn new(regex: Regex, text: String) -> Result<Self, SpaceErr> {
2235 regex.captures(text.as_str()).ok_or("no regex captures")?;
2236 Ok(Self { regex, text })
2237 }
2238}
2239
2240impl VarResolver for RegexCapturesResolver {
2241 fn val(&self, id: &str) -> Result<Substance, ResolverErr> {
2242 let captures = self
2243 .regex
2244 .captures(self.text.as_str())
2245 .expect("expected captures");
2246 match captures.name(id) {
2247 None => Err(ResolverErr::NotFound),
2248 Some(m) => Ok(Substance::Text(m.as_str().to_string())),
2249 }
2250 }
2251}
2252
2253#[derive(Clone)]
2254pub struct MultiVarResolver(Vec<Arc<dyn VarResolver>>);
2255
2256impl Default for MultiVarResolver {
2257 fn default() -> Self {
2258 MultiVarResolver::new()
2259 }
2260}
2261
2262impl MultiVarResolver {
2263 pub fn new() -> Self {
2264 Self(vec![])
2265 }
2266
2267 pub fn push(&mut self, resolver: Arc<dyn VarResolver>) {
2268 self.0.push(resolver);
2269 }
2270}
2271
2272impl VarResolver for MultiVarResolver {
2273 fn val(&self, var: &str) -> Result<Substance, ResolverErr> {
2274 for resolver in &self.0 {
2275 match resolver.val(&var.to_string()) {
2276 Ok(ok) => return Ok(ok),
2277 Err(_) => {}
2278 }
2279 }
2280 Err(ResolverErr::NotFound)
2281 }
2282}
2283
2284pub fn diagnose<I: Clone, O, E: ParseError<I>, F>(
2298 tag: &'static str,
2299 mut f: F,
2300) -> impl FnMut(I) -> IResult<I, O, E>
2301where
2302 I: ToString
2303 + InputLength
2304 + InputTake
2305 + Compare<&'static str>
2306 + InputIter
2307 + Clone
2308 + InputTakeAtPosition,
2309 <I as InputTakeAtPosition>::Item: AsChar,
2310 I: ToString,
2311 F: nom::Parser<I, O, E>,
2312 E: nom::error::ContextError<I>,
2313 O: Clone,
2314{
2315 move |input: I| {
2316 let (next, i) = f.parse(input)?;
2317 Ok((next, i))
2318 }
2319}
2320
2321pub trait SubstParser<T: Sized> {
2322 fn parse_string(&self, string: String) -> Result<T, SpaceErr> {
2323 let span = new_span(string.as_str());
2324 let output = result(self.parse_span(span))?;
2325 Ok(output)
2326 }
2327
2328 fn parse_span<I: Span>(&self, input: I) -> Res<I, T>;
2329}
2330
2331pub fn root_ctx_seg<I: Span, E: ParseError<I>, F>(
2332 mut f: F,
2333) -> impl FnMut(I) -> IResult<I, PointSegCtx, E> + Copy
2334where
2335 F: nom::Parser<I, PointSeg, E> + Copy,
2336 E: nom::error::ContextError<I>,
2337{
2338 move |input: I| match pair(tag::<&str, I, E>(".."), eos)(input.clone()) {
2339 Ok((next, v)) => Ok((
2340 next.clone(),
2341 PointSegCtx::Pop(Trace {
2342 range: next.location_offset() - 2..next.location_offset(),
2343 extra: next.extra(),
2344 }),
2345 )),
2346 Err(err) => match pair(tag::<&str, I, E>("."), eos)(input.clone()) {
2347 Ok((next, _)) => Ok((
2348 next.clone(),
2349 PointSegCtx::Working(Trace {
2350 range: next.location_offset() - 1..next.location_offset(),
2351 extra: next.extra(),
2352 }),
2353 )),
2354 Err(err) => match f.parse(input) {
2355 Ok((next, seg)) => Ok((next, seg.into())),
2356 Err(err) => Err(err),
2357 },
2358 },
2359 }
2360}
2361
2362pub fn working<I: Span, E: ParseError<I>, F>(
2363 mut f: F,
2364) -> impl FnMut(I) -> IResult<I, PointSegCtx, E>
2365where
2366 F: nom::Parser<I, PointSeg, E>,
2367 E: nom::error::ContextError<I>,
2368{
2369 move |input: I| match pair(tag::<&str, I, E>("."), eos)(input.clone()) {
2370 Ok((next, v)) => Ok((
2371 next.clone(),
2372 PointSegCtx::Working(Trace {
2373 range: next.location_offset() - 1..next.location_offset(),
2374 extra: next.extra(),
2375 }),
2376 )),
2377 Err(err) => match f.parse(input.clone()) {
2378 Ok((next, seg)) => Ok((next, seg.into())),
2379 Err(err) => Err(err),
2380 },
2381 }
2382}
2383
2384pub fn pop<I: Span, E: ParseError<I>, F>(
2385 mut f: F,
2386) -> impl FnMut(I) -> IResult<I, PointSegCtx, E> + Copy
2387where
2388 F: nom::Parser<I, PointSeg, E> + Copy,
2389 E: nom::error::ContextError<I>,
2390{
2391 move |input: I| match pair(tag::<&str, I, E>(".."), eos)(input.clone()) {
2392 Ok((next, v)) => Ok((
2393 next.clone(),
2394 PointSegCtx::Working(Trace {
2395 range: next.location_offset() - 2..next.location_offset(),
2396 extra: next.extra(),
2397 }),
2398 )),
2399 Err(err) => match f.parse(input.clone()) {
2400 Ok((next, seg)) => Ok((next, seg.into())),
2401 Err(err) => Err(err),
2402 },
2403 }
2404}
2405
2406pub fn base_seg<I, F, S, E>(mut f: F) -> impl FnMut(I) -> IResult<I, S, E>
2407where
2408 I: Span,
2409 F: nom::Parser<I, S, E> + Copy,
2410 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2411 S: PointSegment,
2412{
2413 move |input: I| preceded(tag(":"), f)(input)
2414}
2415
2416pub fn mesh_seg<I: Span, E: ParseError<I>, F, S1, S2>(
2417 mut f: F,
2418) -> impl FnMut(I) -> IResult<I, S2, E>
2419where
2420 F: nom::Parser<I, S1, E> + Copy,
2421 E: nom::error::ContextError<I>,
2422 S1: PointSegment + Into<S2>,
2423 S2: PointSegment,
2424{
2425 move |input: I| {
2426 tuple((seg_delim, f, eos))(input).map(|(next, (delim, seg, _))| (next, seg.into()))
2427 }
2428}
2429
2430pub fn seg_delim<I: Span, E>(input: I) -> IResult<I, PointSegDelim, E>
2432where
2433 I: ToString
2434 + Clone
2435 + InputLength
2436 + InputTake
2437 + Compare<&'static str>
2438 + InputIter
2439 + InputTakeAtPosition,
2440 <I as InputTakeAtPosition>::Item: AsChar + Clone,
2441 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2442{
2443 alt((
2444 value(PointSegDelim::File, tag("/")),
2445 value(PointSegDelim::Mesh, tag(":")),
2446 ))(input)
2447 .map(|(next, delim)| (next, delim))
2448}
2449
2450pub fn eos<I: Span, E>(input: I) -> IResult<I, (), E>
2452where
2453 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2454{
2455 peek(alt((tag("/"), tag(":"), tag("%"), space1, eof)))(input).map(|(next, _)| (next, ()))
2456}
2457
2458pub fn variable_name<I: Span>(input: I) -> Res<I, I> {
2525 recognize(pair(lowercase1, opt(skewer_dot)))(input).map(|(next, name)| (next, name))
2526}
2527
2528pub fn ispan<'a, I: Clone, O, E: ParseError<I>, F>(
2529 mut f: F,
2530) -> impl FnMut(I) -> IResult<I, Spanned<I, O>, E>
2531where
2532 I: ToString
2533 + InputLength
2534 + InputTake
2535 + Compare<&'static str>
2536 + InputIter
2537 + Clone
2538 + InputTakeAtPosition,
2539 <I as InputTakeAtPosition>::Item: AsChar,
2540 F: nom::Parser<I, O, E>,
2541 E: nom::error::ContextError<I>,
2542 O: Clone + FromStr<Err = SpaceErr>,
2543{
2544 move |input: I| {
2545 let (next, element) = f.parse(input.clone())?;
2546 Ok((next, Spanned::new(element, input.clone())))
2547 }
2548}
2549
2550pub fn sub<I: Span, O, F>(mut f: F) -> impl FnMut(I) -> Res<I, Spanned<I, O>>
2551where
2552 F: nom::Parser<I, O, ErrorTree<I>>,
2553 O: Clone,
2554{
2555 move |input: I| {
2556 let (next, element) = f.parse(input.clone())?;
2557 Ok((
2558 next.clone(),
2559 Spanned::new(element, input.slice(0..(input.len() - next.len()))),
2560 ))
2561 }
2562}
2563
2564pub fn access_grant_kind<I: Span>(input: I) -> Res<I, AccessGrantKind> {
2565 tuple((
2566 context(
2567 "access_grant_kind",
2568 peek(alt((
2569 tuple((tag("perm"), space1)),
2570 tuple((tag("priv"), space1)),
2571 ))),
2572 ),
2573 alt((access_grant_kind_perm, access_grant_kind_priv)),
2574 ))(input)
2575 .map(|(next, (_, kind))| (next, kind))
2576}
2577
2578pub fn access_grant_kind_priv<I: Span>(input: I) -> Res<I, AccessGrantKind> {
2579 tuple((
2580 tag("priv"),
2581 context("access_grant:priv", tuple((space1, privilege))),
2582 ))(input)
2583 .map(|(next, (_, (_, privilege)))| (next, AccessGrantKindDef::Privilege(privilege)))
2584}
2585
2586pub fn access_grant_kind_perm<I: Span>(input: I) -> Res<I, AccessGrantKind> {
2587 tuple((
2588 tag("perm"),
2589 context("access_grant:perm", tuple((space1, permissions_mask))),
2590 ))(input)
2591 .map(|(next, (_, (_, perms)))| (next, AccessGrantKindDef::PermissionsMask(perms)))
2592}
2593
2594pub fn privilege<I: Span>(input: I) -> Res<I, Privilege> {
2595 context("privilege", alt((tag("*"), skewer_colon)))(input).map(|(next, prv)| {
2596 let prv = match prv.to_string().as_str() {
2597 "*" => Privilege::Full,
2598 prv => Privilege::Single(prv.to_string()),
2599 };
2600 (next, prv)
2601 })
2602}
2603
2604pub fn permissions_mask<I: Span>(input: I) -> Res<I, PermissionsMask> {
2605 context(
2606 "permissions_mask",
2607 tuple((
2608 alt((
2609 value(PermissionsMaskKind::Or, char('+')),
2610 value(PermissionsMaskKind::And, char('&')),
2611 )),
2612 permissions,
2613 )),
2614 )(input)
2615 .map(|(next, (kind, permissions))| {
2616 let mask = PermissionsMask { kind, permissions };
2617
2618 (next, mask)
2619 })
2620}
2621
2622pub fn permissions<I: Span>(input: I) -> Res<I, Permissions> {
2623 context(
2624 "permissions",
2625 tuple((child_perms, tag("-"), particle_perms)),
2626 )(input)
2627 .map(|(next, (child, _, particle))| {
2628 let permissions = Permissions { child, particle };
2629 (next, permissions)
2630 })
2631}
2632
2633pub fn child_perms<I: Span>(input: I) -> Res<I, ChildPerms> {
2634 context(
2635 "child_perms",
2636 alt((
2637 tuple((
2638 alt((value(false, char('c')), value(true, char('C')))),
2639 alt((value(false, char('s')), value(true, char('S')))),
2640 alt((value(false, char('d')), value(true, char('D')))),
2641 )),
2642 fail,
2643 )),
2644 )(input)
2645 .map(|(next, (create, select, delete))| {
2646 let block = ChildPerms {
2647 create,
2648 select,
2649 delete,
2650 };
2651 (next, block)
2652 })
2653}
2654
2655pub fn particle_perms<I: Span>(input: I) -> Res<I, ParticlePerms> {
2656 context(
2657 "particle_perms",
2658 tuple((
2659 alt((value(false, char('r')), value(true, char('R')))),
2660 alt((value(false, char('w')), value(true, char('W')))),
2661 alt((value(false, char('x')), value(true, char('X')))),
2662 )),
2663 )(input)
2664 .map(|(next, (read, write, execute))| {
2665 let block = ParticlePerms {
2666 read,
2667 write,
2668 execute,
2669 };
2670 (next, block)
2671 })
2672}
2673
2674pub fn none<I: Span, O, E>(input: I) -> IResult<I, Option<O>, E> {
2682 Ok((input, None))
2683}
2684
2685pub fn some<I: Span, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Option<O>, E>
2686where
2687 I: ToString
2688 + InputLength
2689 + InputTake
2690 + Compare<&'static str>
2691 + InputIter
2692 + Clone
2693 + InputTakeAtPosition,
2694 <I as InputTakeAtPosition>::Item: AsChar,
2695 I: ToString,
2696 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2697 I: nom::Slice<std::ops::RangeFrom<usize>>,
2698 <I as InputIter>::Item: AsChar,
2699 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2700 F: nom::Parser<I, O, E> + Clone,
2701{
2702 move |input: I| {
2703 f.clone()
2704 .parse(input)
2705 .map(|(next, output)| (next, Some(output)))
2706 }
2707}
2708
2709pub fn lex_block_alt<I: Span, E>(
2710 kinds: Vec<BlockKind>,
2711) -> impl FnMut(I) -> IResult<I, LexBlock<I>, E>
2712where
2713 I: ToString
2714 + InputLength
2715 + InputTake
2716 + Compare<&'static str>
2717 + InputIter
2718 + Clone
2719 + InputTakeAtPosition,
2720 <I as InputTakeAtPosition>::Item: AsChar,
2721 I: ToString,
2722 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2723 I: nom::Slice<std::ops::RangeFrom<usize>>,
2724 <I as InputIter>::Item: AsChar + Copy,
2725 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2726{
2727 move |input: I| {
2728 for kind in &kinds {
2729 let result = lex_block(kind.clone())(input.clone());
2730 match &result {
2731 Ok((next, block)) => return result,
2732 Err(err) => {
2733 match err {
2734 nom::Err::Incomplete(Needed) => return result,
2735 nom::Err::Error(e) => {
2736 }
2738 nom::Err::Failure(e) => return result,
2739 }
2740 }
2741 }
2742 }
2743
2744 Err(nom::Err::Failure(E::from_error_kind(
2745 input.clone(),
2746 ErrorKind::Alt,
2747 )))
2748 }
2749}
2750
2751pub fn lex_block<I: Span, E>(kind: BlockKind) -> impl FnMut(I) -> IResult<I, LexBlock<I>, E>
2752where
2753 I: ToString
2754 + InputLength
2755 + InputTake
2756 + Compare<&'static str>
2757 + InputIter
2758 + Clone
2759 + InputTakeAtPosition,
2760 <I as InputTakeAtPosition>::Item: AsChar,
2761 I: ToString,
2762 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2763 I: nom::Slice<std::ops::RangeFrom<usize>>,
2764 <I as InputIter>::Item: AsChar + Copy,
2765 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2766{
2767 move |input: I| match kind {
2768 BlockKind::Nested(kind) => lex_nested_block(kind).parse(input),
2769 BlockKind::Terminated(kind) => lex_terminated_block(kind).parse(input),
2770 BlockKind::Delimited(kind) => lex_delimited_block(kind).parse(input),
2771 BlockKind::Partial => {
2772 eprintln!("parser should not be seeking partial block kinds...");
2773 Err(nom::Err::Failure(E::from_error_kind(
2774 input,
2775 ErrorKind::IsNot,
2776 )))
2777 }
2778 }
2779}
2780
2781pub fn lex_terminated_block<I: Span, E>(
2782 kind: TerminatedBlockKind,
2783) -> impl FnMut(I) -> IResult<I, LexBlock<I>, E>
2784where
2785 I: ToString
2786 + InputLength
2787 + InputTake
2788 + Compare<&'static str>
2789 + InputIter
2790 + Clone
2791 + InputTakeAtPosition,
2792 <I as InputTakeAtPosition>::Item: AsChar,
2793 I: ToString,
2794 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2795 I: nom::Slice<std::ops::RangeFrom<usize>>,
2796 <I as InputIter>::Item: AsChar,
2797 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2798{
2799 move |input: I| {
2800 terminated(
2801 recognize(many0(satisfy(|c| c != kind.as_char()))),
2802 tag(kind.tag()),
2803 )(input)
2804 .map(|(next, content)| {
2805 let block = LexBlock {
2806 kind: BlockKind::Terminated(kind),
2807 content,
2808 data: (),
2809 };
2810
2811 (next, block)
2812 })
2813 }
2814}
2815
2816pub fn lex_nested_block<I: Span, E>(
2819 kind: NestedBlockKind,
2820) -> impl FnMut(I) -> IResult<I, LexBlock<I>, E>
2821where
2822 I: ToString
2823 + InputLength
2824 + InputTake
2825 + Compare<&'static str>
2826 + InputIter
2827 + Clone
2828 + InputTakeAtPosition,
2829 <I as InputTakeAtPosition>::Item: AsChar,
2830 I: ToString,
2831 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2832 I: nom::Slice<std::ops::RangeFrom<usize>>,
2833 <I as InputIter>::Item: AsChar + Copy,
2834 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2835{
2836 move |input: I| {
2837 let (next, content) = context(
2838 kind.context(),
2839 delimited(
2840 context(kind.open_context(), tag(kind.open())),
2841 recognize(many0(alt((
2842 recognize(lex_nested_block(kind.clone())),
2843 recognize(tuple((
2844 not(peek(tag(kind.close()))),
2845 alt((recognize(pair(tag("\\"), anychar)), recognize(anychar))),
2846 ))),
2847 )))),
2848 context(kind.close_context(), cut(tag(kind.close()))),
2849 ),
2850 )(input)?;
2851 let block = Block::parse(BlockKind::Nested(kind), content);
2852 Ok((next, block))
2853 }
2854}
2855
2856pub fn nested_block_content<I: Span>(kind: NestedBlockKind) -> impl FnMut(I) -> Res<I, I> {
2857 move |input: I| nested_block(kind)(input).map(|(next, block)| (next, block.content))
2858}
2859
2860pub fn nested_block<I: Span>(kind: NestedBlockKind) -> impl FnMut(I) -> Res<I, Block<I, ()>> {
2861 move |input: I| {
2862 let (next, content) = context(
2863 kind.context(),
2864 delimited(
2865 context(kind.open_context(), tag(kind.open())),
2866 recognize(many0(tuple((
2867 not(peek(tag(kind.close()))),
2868 context(
2869 kind.unpaired_closing_scope(),
2870 cut(peek(expected_block_terminator_or_non_terminator(
2871 kind.clone(),
2872 ))),
2873 ),
2874 alt((
2875 recognize(pair(peek(block_open), any_block)),
2876 recognize(anychar),
2877 )),
2878 )))),
2879 context(kind.close_context(), cut(tag(kind.close()))),
2880 ),
2881 )(input)?;
2882 let block = Block::parse(BlockKind::Nested(kind), content);
2883 Ok((next, block))
2884 }
2885}
2886
2887pub fn lex_delimited_block<I: Span, E>(
2888 kind: DelimitedBlockKind,
2889) -> impl FnMut(I) -> IResult<I, LexBlock<I>, E>
2890where
2891 I: ToString
2892 + InputLength
2893 + InputTake
2894 + Compare<&'static str>
2895 + InputIter
2896 + Clone
2897 + InputTakeAtPosition,
2898 <I as InputTakeAtPosition>::Item: AsChar,
2899 I: ToString,
2900 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2901 I: nom::Slice<std::ops::RangeFrom<usize>>,
2902 <I as InputIter>::Item: AsChar + Copy,
2903 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2904{
2905 move |input: I| {
2906 let (next, content) = context(
2907 kind.context(),
2908 delimited(
2909 context(kind.context(), tag(kind.delim())),
2910 recognize(many0(tuple((
2911 not(peek(tag(kind.delim()))),
2912 alt((recognize(pair(tag("\\"), anychar)), recognize(anychar))),
2913 )))),
2914 context(kind.missing_close_context(), cut(tag(kind.delim()))),
2915 ),
2916 )(input)?;
2917 let block = Block::parse(BlockKind::Delimited(kind), content);
2918 Ok((next, block))
2919 }
2920}
2921
2922fn block_open<I: Span>(input: I) -> Res<I, NestedBlockKind> {
2923 alt((
2924 value(NestedBlockKind::Curly, tag(NestedBlockKind::Curly.open())),
2925 value(NestedBlockKind::Angle, tag(NestedBlockKind::Angle.open())),
2926 value(NestedBlockKind::Parens, tag(NestedBlockKind::Parens.open())),
2927 value(NestedBlockKind::Square, tag(NestedBlockKind::Square.open())),
2928 ))(input)
2929}
2930
2931fn any_soround_lex_block<I: Span, E>(input: I) -> IResult<I, LexBlock<I>, E>
2932where
2933 I: ToString
2934 + InputLength
2935 + InputTake
2936 + Compare<&'static str>
2937 + InputIter
2938 + Clone
2939 + InputTakeAtPosition,
2940 <I as InputTakeAtPosition>::Item: AsChar,
2941 I: ToString,
2942 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
2943 I: nom::Slice<std::ops::RangeFrom<usize>>,
2944 <I as InputIter>::Item: AsChar + Copy,
2945 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
2946{
2947 alt((
2948 lex_nested_block(NestedBlockKind::Curly),
2949 lex_nested_block(NestedBlockKind::Angle),
2950 lex_nested_block(NestedBlockKind::Parens),
2951 lex_nested_block(NestedBlockKind::Square),
2952 lex_delimited_block(DelimitedBlockKind::DoubleQuotes),
2953 lex_delimited_block(DelimitedBlockKind::SingleQuotes),
2954 ))(input)
2955}
2956
2957fn any_block<I: Span>(input: I) -> Res<I, LexBlock<I>> {
2958 alt((
2959 nested_block(NestedBlockKind::Curly),
2960 nested_block(NestedBlockKind::Angle),
2961 nested_block(NestedBlockKind::Parens),
2962 nested_block(NestedBlockKind::Square),
2963 lex_delimited_block(DelimitedBlockKind::DoubleQuotes),
2964 lex_delimited_block(DelimitedBlockKind::SingleQuotes),
2965 ))(input)
2966}
2967
2968pub fn expected_block_terminator_or_non_terminator<I: Span>(
2969 expect: NestedBlockKind,
2970) -> impl FnMut(I) -> Res<I, ()>
2971where
2972 I: InputIter + InputLength + Slice<RangeFrom<usize>>,
2973 <I as InputIter>::Item: AsChar,
2974 I: Clone,
2975{
2976 move |input: I| -> Res<I, ()> {
2977 verify(anychar, move |c| {
2978 if NestedBlockKind::is_block_terminator(*c) {
2979 *c == expect.close_as_char()
2980 } else {
2981 true
2982 }
2983 })(input)
2984 .map(|(next, _)| (next, ()))
2985 }
2986}
2987
2988pub fn unwrap_block<I: Span, F, O>(kind: BlockKind, mut f: F) -> impl FnMut(I) -> Res<I, O>
3024where
3025 F: FnMut(I) -> Res<I, O>,
3026{
3027 move |input: I| {
3028 let (next, block) = lex_block(kind)(input)?;
3029 let (_, content) = f.parse(block.content)?;
3030 Ok((next, content))
3032 }
3033}
3034
3035pub fn lex_child_scopes<I: Span>(parent: LexScope<I>) -> Result<LexParentScope<I>, SpaceErr> {
3036 if parent.selector.children.is_some() {
3037 let (_, child_selector) = all_consuming(lex_scope_selector)(
3038 parent
3039 .selector
3040 .children
3041 .as_ref()
3042 .expect("child names...")
3043 .clone(),
3044 )?;
3045
3046 let child = LexScope::new(child_selector.into(), parent.block);
3047
3048 Ok(LexParentScope {
3049 selector: parent.selector.clone(),
3050 pipeline_step: None,
3051 block: vec![child],
3052 })
3053 } else {
3054 let scopes = lex_scopes(parent.block.content)?;
3055
3056 Ok(LexParentScope {
3057 selector: parent.selector.into(),
3058 pipeline_step: parent.pipeline_step,
3059 block: scopes,
3060 })
3061 }
3062}
3063
3064pub fn lex_scope<I: Span>(input: I) -> Res<I, LexScope<I>> {
3065 context(
3066 "scope",
3067 tuple((
3068 peek(alt((tag("*"), alpha1, tag("<")))),
3069 lex_scope_selector,
3070 multispace1,
3071 lex_scope_pipeline_step_and_block,
3072 )),
3073 )(input)
3074 .map(|(next, (_, selector, _, (pipeline_step, block)))| {
3075 let scope = LexScope {
3076 selector,
3077 pipeline_step,
3078 block,
3079 };
3080 (next, scope)
3081 })
3082}
3083
3084pub fn lex_scoped_block_kind<I: Span>(input: I) -> Res<I, BlockKind> {
3085 alt((
3086 value(
3087 BlockKind::Nested(NestedBlockKind::Curly),
3088 recognize(tuple((
3089 multispace0,
3090 rough_pipeline_step,
3091 multispace0,
3092 lex_block(BlockKind::Nested(NestedBlockKind::Curly)),
3093 ))),
3094 ),
3095 value(
3096 BlockKind::Terminated(TerminatedBlockKind::Semicolon),
3097 recognize(pair(
3098 rough_pipeline_step,
3099 lex_block(BlockKind::Terminated(TerminatedBlockKind::Semicolon)),
3100 )),
3101 ),
3102 ))(input)
3103}
3104
3105pub fn lex_scope_pipeline_step_and_block<I: Span>(input: I) -> Res<I, (Option<I>, LexBlock<I>)> {
3106 let (_, block_kind) = peek(lex_scoped_block_kind)(input.clone())?;
3107 match block_kind {
3108 BlockKind::Nested(_) => tuple((
3109 rough_pipeline_step,
3110 multispace1,
3111 lex_block(BlockKind::Nested(NestedBlockKind::Curly)),
3112 ))(input)
3113 .map(|(next, (step, _, block))| (next, (Some(step), block))),
3114 BlockKind::Terminated(_) => {
3115 lex_block(BlockKind::Terminated(TerminatedBlockKind::Semicolon))(input)
3116 .map(|(next, block)| (next, (None, block)))
3117 }
3118 _ => unimplemented!(),
3119 }
3120}
3121
3122pub fn lex_sub_scope_selectors_and_filters_and_block<I: Span>(input: I) -> Res<I, LexBlock<I>> {
3123 recognize(pair(
3124 nested_block_content(NestedBlockKind::Angle),
3125 tuple((
3126 opt(scope_filters),
3127 multispace0,
3128 opt(rough_pipeline_step),
3129 multispace0,
3130 lex_block_alt(vec![
3131 BlockKind::Nested(NestedBlockKind::Curly),
3132 BlockKind::Terminated(TerminatedBlockKind::Semicolon),
3133 ]),
3134 )),
3135 ))(input)
3136 .map(|(next, content)| {
3137 (
3138 next,
3139 LexBlock {
3140 kind: BlockKind::Partial,
3141 content,
3142 data: (),
3143 },
3144 )
3145 })
3146}
3147
3148pub fn root_scope<I: Span>(input: I) -> Res<I, LexRootScope<I>> {
3149 context(
3150 "root-scope",
3151 tuple((
3152 root_scope_selector,
3153 multispace0,
3154 context("root-scope:block", cut(peek(tag("{")))),
3155 context(
3156 "root-scope:block",
3157 cut(lex_nested_block(NestedBlockKind::Curly)),
3158 ),
3159 )),
3160 )(input)
3161 .map(|(next, (selector, _, _, block))| {
3162 let scope = LexRootScope::new(selector, block);
3163 (next, scope)
3164 })
3165}
3166
3167pub fn lex_scopes<I: Span>(input: I) -> Result<Vec<LexScope<I>>, SpaceErr> {
3168 if input.len() == 0 {
3169 return Ok(vec![]);
3170 }
3171
3172 if wrapper(input.clone(), all_consuming(multispace1)).is_ok() {
3173 return Ok(vec![]);
3174 }
3175
3176 result(
3177 context(
3178 "parsed-scopes",
3179 all_consuming(many0(delimited(
3180 multispace0,
3181 context(
3182 "scope",
3183 pair(peek(not(alt((tag("}"), eof)))), cut(lex_scope)),
3184 ),
3185 multispace0,
3186 ))),
3187 )(input)
3188 .map(|(next, scopes)| {
3189 let scopes: Vec<LexScope<I>> = scopes.into_iter().map(|scope| scope.1).collect();
3190 (next, scopes)
3191 }),
3192 )
3193}
3194
3195pub fn next_stacked_name<I: Span>(input: I) -> Res<I, (I, Option<I>)> {
3213 match wrapper(
3214 input.clone(),
3215 pair(
3216 peek(tag("<")),
3217 tuple((
3218 tag("<"),
3219 pair(
3220 context("scope-selector", alt((alphanumeric1, tag("*")))),
3221 opt(recognize(nested_block(NestedBlockKind::Angle))),
3222 ),
3223 tag(">"),
3224 )),
3225 ),
3226 )
3227 .map(|(next, (_, (_, (name, children), _)))| (next, (name, children)))
3228 {
3229 Ok((next, (name, children))) => return Ok((next, (name, children))),
3230 Err(_) => {}
3231 }
3232 pair(
3233 context("scope-selector", cut(alt((alphanumeric1, tag("*"))))),
3234 opt(recognize(nested_block(NestedBlockKind::Angle))),
3235 )(input)
3236}
3237
3238pub fn lex_scope_selector<I: Span>(input: I) -> Res<I, LexScopeSelector<I>> {
3239 let (next, ((name, children), filters, path)) = context(
3240 "parsed-scope-selector",
3241 tuple((next_stacked_name, scope_filters, opt(path_regex))),
3242 )(input.clone())?;
3243
3244 Ok((next, LexScopeSelector::new(name, filters, path, children)))
3245}
3246
3247pub fn lex_name_stack<I: Span>(mut input: I) -> Res<I, Vec<I>> {
3248 let mut stack = vec![];
3249 let (next, (name, mut children)) = next_stacked_name(input)?;
3250 stack.push(name);
3251 loop {
3252 match &children {
3253 None => {
3254 break;
3255 }
3256 Some(children) => {
3257 input = children.clone();
3258 }
3259 }
3260 let (_, (name, c)) = next_stacked_name(input)?;
3261 children = c;
3262 stack.push(name);
3263 }
3264
3265 Ok((next, stack))
3266}
3267
3268pub struct LexRouteSelector<I> {
3269 pub names: Vec<I>,
3270 pub filters: ScopeFiltersDef<I>,
3271 pub path: Option<I>,
3272}
3273
3274pub fn lex_route_selector<I: Span>(input: I) -> Res<I, LexRouteSelector<I>> {
3275 tuple((lex_name_stack, scope_filters, opt(path_regex)))(input).map(
3276 |(next, (names, filters, path))| {
3277 let selector = LexRouteSelector {
3278 names,
3279 filters,
3280 path,
3281 };
3282 (next, selector)
3283 },
3284 )
3285}
3286
3287pub fn wrapper<I: Span, O, F>(input: I, mut f: F) -> Res<I, O>
3288where
3289 F: FnMut(I) -> Res<I, O>,
3290{
3291 f.parse(input)
3292}
3293
3294pub fn parse_inner_block<I, E, F>(
3295 kind: NestedBlockKind,
3296 mut f: &F,
3297) -> impl FnMut(I) -> IResult<I, I, E> + '_
3298where
3299 I: Span,
3300 &'static str: FindToken<<I as InputTakeAtPosition>::Item>,
3301
3302 I: ToString
3303 + InputLength
3304 + InputTake
3305 + Compare<&'static str>
3306 + InputIter
3307 + Clone
3308 + InputTakeAtPosition,
3309 <I as InputTakeAtPosition>::Item: AsChar + Copy,
3310 I: ToString,
3311 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
3312 I: nom::Slice<std::ops::RangeFrom<usize>>,
3313 <I as InputIter>::Item: AsChar + Copy,
3314 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
3315 F: Fn(char) -> bool,
3316 F: Clone,
3317{
3318 move |input: I| {
3319 let (next, rtn) = alt((
3320 delimited(
3321 tag(kind.open()),
3322 recognize(many1(alt((
3323 recognize(any_soround_lex_block),
3324 recognize(verify(anychar, move |c| {
3325 f(*c) && *c != kind.close_as_char()
3326 })),
3327 )))),
3328 tag(kind.close()),
3329 ),
3330 recognize(many1(verify(anychar, move |c| {
3331 f(*c) && *c != kind.close_as_char()
3332 }))),
3333 ))(input)?;
3334 Ok((next, rtn))
3335 }
3336}
3337
3338pub fn parse_include_blocks<I, O2, E, F>(
3339 kind: NestedBlockKind,
3340 mut f: F,
3341) -> impl FnMut(I) -> IResult<I, I, E>
3342where
3343 I: Span,
3344 &'static str: FindToken<<I as InputTakeAtPosition>::Item>,
3345
3346 I: ToString
3347 + InputLength
3348 + InputTake
3349 + Compare<&'static str>
3350 + InputIter
3351 + Clone
3352 + InputTakeAtPosition,
3353 <I as InputTakeAtPosition>::Item: AsChar,
3354 I: ToString,
3355 I: Offset + nom::Slice<std::ops::RangeTo<usize>>,
3356 I: nom::Slice<std::ops::RangeFrom<usize>>,
3357 <I as InputIter>::Item: AsChar,
3358 E: nom::error::ContextError<I> + nom::error::ParseError<I>,
3359 F: FnMut(I) -> IResult<I, O2, E>,
3360 F: Clone,
3361 <I as InputIter>::Item: std::marker::Copy,
3362{
3363 move |input: I| {
3364 recognize(many0(alt((
3365 recognize(any_soround_lex_block),
3366 recognize(verify(anychar, move |c| *c != kind.close_as_char())),
3367 ))))(input)
3368 }
3369}
3370
3371pub fn scope_filters<I: Span>(input: I) -> Res<I, ScopeFiltersDef<I>> {
3372 pair(opt(scope_filter), many0(preceded(tag("-"), scope_filter)))(input).map(
3373 |(next, (first, mut many_filters))| {
3374 let mut filters = vec![];
3375 match first {
3376 None => {}
3377 Some(first) => {
3378 filters.push(first);
3379 }
3380 }
3381 filters.append(&mut many_filters);
3382 let filters = ScopeFiltersDef { filters };
3383 (next, filters)
3384 },
3385 )
3386}
3387
3388pub fn scope_filter<I: Span>(input: I) -> Res<I, ScopeFilterDef<I>> {
3389 delimited(
3390 tag("("),
3391 context(
3392 "scope-filter",
3393 cut(tuple((
3394 context("filter-name", cut(scope_name)),
3395 opt(context(
3396 "filter-arguments",
3397 preceded(
3398 multispace1,
3399 parse_include_blocks(NestedBlockKind::Parens, args),
3400 ),
3401 )),
3402 ))),
3403 ),
3404 tag(")"),
3405 )(input)
3406 .map(|(next, (name, args))| {
3407 let filter = ScopeFilterDef { name, args };
3408 (next, filter)
3409 })
3410}
3411
3412pub fn scope_name<I>(input: I) -> Res<I, I>
3413where
3414 I: Span,
3415{
3416 recognize(pair(
3417 skewer_case_chars,
3418 peek(alt((eof, multispace1, tag(")")))),
3419 ))(input)
3420}
3421
3422pub fn root_scope_selector<I: Span>(input: I) -> Res<I, RootScopeSelector<I, Spanned<I, Version>>> {
3423 context(
3424 "root-scope-selector",
3425 cut(preceded(
3426 multispace0,
3427 pair(
3428 context("root-scope-selector:name", cut(root_scope_selector_name)),
3429 context("root-scope-selector:version", cut(scope_version)),
3430 ),
3431 )),
3432 )(input)
3433 .map(|(next, (name, version))| (next, RootScopeSelector { version, name }))
3434}
3435
3436pub fn scope_version<I: Span>(input: I) -> Res<I, Spanned<I, Version>> {
3437 context(
3438 "scope-selector-version",
3439 tuple((
3440 tag("(version="),
3441 sub(version),
3442 context("scope-selector-version-closing-tag", tag(")")),
3443 )),
3444 )(input)
3445 .map(|((next, (_, version, _)))| (next, version))
3446}
3447
3448pub fn scope_selector_name<I: Span>(input: I) -> Res<I, I> {
3468 context(
3469 "scope-selector-name",
3470 delimited(
3471 (context(
3472 "scope-selector-name:expect-alphanumeric-leading",
3473 cut(peek(alpha1)),
3474 )),
3475 alphanumeric1,
3476 context(
3477 "scope-selector-name:expect-termination",
3478 cut(peek(alt((
3479 multispace1,
3480 tag("{"),
3481 tag("("),
3482 tag("<"),
3483 tag(">"),
3484 )))),
3485 ),
3486 ),
3487 )(input)
3488 .map(|(next, name)| (next, name))
3489}
3490
3491pub fn root_scope_selector_name<I: Span>(input: I) -> Res<I, I> {
3492 context(
3493 "root-scope-selector-name",
3494 pair((peek(alpha1)), alphanumeric1),
3495 )(input)
3496 .map(|(next, (_, name))| (next, name))
3497}
3498
3499pub fn lex_root_scope<I: Span>(span: I) -> Result<LexRootScope<I>, SpaceErr> {
3500 let root_scope = result(delimited(multispace0, root_scope, multispace0)(span))?;
3501 Ok(root_scope)
3502}
3503
3504pub fn method_kind<I: Span>(input: I) -> Res<I, MethodKind> {
3505 let (next, v) = recognize(alt((tag("Cmd"), tag("Ext"), tag("Http"), tag("Hyp"))))(input)?;
3506 Ok((next, MethodKind::from_str(v.to_string().as_str()).unwrap()))
3507}
3508
3509pub mod model {
3510 use std::collections::HashMap;
3511 use std::fmt::{Formatter, Write};
3512 use std::marker::PhantomData;
3513 use std::ops::{Deref, DerefMut};
3514 use std::rc::Rc;
3515 use std::str::FromStr;
3516
3517 use bincode::Options;
3518 use nom::bytes::complete::tag;
3519 use nom::character::complete::{alphanumeric1, multispace0, multispace1, satisfy};
3520 use nom::combinator::{cut, fail, not, peek, recognize, value};
3521 use nom::sequence::delimited;
3522 use regex::Regex;
3523 use serde::de::Visitor;
3524 use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
3525
3526 use cosmic_nom::{new_span, Res, Span, Trace, Tw};
3527
3528 use crate::command::direct::CmdKind;
3529 use crate::config::bind::{
3530 BindConfig, PipelineStepCtx, PipelineStepDef, PipelineStepVar, PipelineStopCtx,
3531 PipelineStopDef, PipelineStopVar, WaveDirection,
3532 };
3533 use crate::err::{ParseErrs, SpaceErr};
3534 use crate::loc::Version;
3535 use crate::parse::error::result;
3536 use crate::parse::{
3537 Assignment, camel_case_chars, CtxResolver, Env, filepath_chars, http_method,
3538 lex_child_scopes, method_kind, pipeline, rc_command_type,
3539 ResolverErr, SubstParser, value_pattern, wrapped_cmd_method, wrapped_ext_method, wrapped_http_method,
3540 wrapped_sys_method,
3541 };
3542 use crate::point::{Point, PointCtx, PointVar};
3543 use crate::util::{HttpMethodPattern, StringMatcher, ToResolved, ValueMatcher, ValuePattern};
3544 use crate::wave::core::http2::HttpMethod;
3545 use crate::wave::core::{DirectedCore, Method, MethodKind};
3546 use crate::wave::{DirectedWave, Ping, SingularDirectedWave};
3547
3548 #[derive(Clone)]
3549 pub struct ScopeSelectorAndFiltersDef<S, I> {
3550 pub selector: S,
3551 pub filters: ScopeFiltersDef<I>,
3552 }
3553
3554 impl<S, I> Deref for ScopeSelectorAndFiltersDef<S, I> {
3555 type Target = S;
3556
3557 fn deref(&self) -> &Self::Target {
3558 &self.selector
3559 }
3560 }
3561
3562 impl<S, I> ScopeSelectorAndFiltersDef<S, I> {
3563 pub fn new(selector: S, filters: ScopeFiltersDef<I>) -> Self {
3564 Self { selector, filters }
3565 }
3566 }
3567
3568 pub enum ParsePhase {
3569 Root,
3570 SubScopes,
3571 }
3572
3573 #[derive(Clone)]
3574 pub struct Spanned<I, E>
3575 where
3576 E: Clone,
3577 I: ToString,
3578 {
3579 pub span: I,
3580 pub element: E,
3581 }
3582
3583 impl<I, E> Spanned<I, E>
3584 where
3585 E: Clone,
3586 I: ToString,
3587 {
3588 pub fn new(element: E, span: I) -> Spanned<I, E> {
3589 Self { span, element }
3590 }
3591 }
3592
3593 impl<I, E> Spanned<I, E>
3594 where
3595 E: Clone + ToString,
3596 I: ToString,
3597 {
3598 pub fn len(&self) -> usize {
3599 self.element.to_string().len()
3600 }
3601 }
3602
3603 impl<I, E> ToString for Spanned<I, E>
3604 where
3605 E: Clone + ToString,
3606 I: ToString,
3607 {
3608 fn to_string(&self) -> String {
3609 self.element.to_string()
3610 }
3611 }
3612
3613 impl<I, E> Deref for Spanned<I, E>
3614 where
3615 E: Clone,
3616 I: ToString,
3617 {
3618 type Target = E;
3619
3620 fn deref(&self) -> &Self::Target {
3621 &self.element
3622 }
3623 }
3624
3625 impl<I, E> DerefMut for Spanned<I, E>
3626 where
3627 E: Clone,
3628 I: ToString,
3629 {
3630 fn deref_mut(&mut self) -> &mut Self::Target {
3631 &mut self.element
3632 }
3633 }
3634
3635 #[derive(Clone, Eq, PartialEq, Hash)]
3636 pub struct RootScopeSelector<I, V> {
3637 pub name: I,
3638 pub version: V,
3639 }
3640
3641 impl<I, V> RootScopeSelector<I, V> {
3642 pub fn new(name: I, version: V) -> Self {
3643 RootScopeSelector { name, version }
3644 }
3645 }
3646
3647 impl<I: ToString, V: ToString> RootScopeSelector<I, V> {
3648 pub fn to_concrete(self) -> Result<RootScopeSelector<String, Version>, SpaceErr> {
3649 Ok(RootScopeSelector {
3650 name: self.name.to_string(),
3651 version: Version::from_str(self.version.to_string().as_str())?,
3652 })
3653 }
3654 }
3655
3656 impl RouteScope {
3657 pub fn select(&self, directed: &DirectedWave) -> Vec<&WaveScope> {
3658 let mut scopes = vec![];
3659 for scope in &self.block {
3660 if scope.selector.is_match(directed).is_ok() {
3661 scopes.push(scope);
3662 }
3663 }
3664 scopes
3665 }
3666 }
3667
3668 #[derive(Clone)]
3669 pub struct RouteScopeSelector {
3670 pub selector: ScopeSelectorDef<String, Regex>,
3671 }
3672
3673 impl RouteScopeSelector {
3674 pub fn new<I: ToString>(path: Option<I>) -> Result<Self, SpaceErr> {
3675 let path = match path {
3676 None => Regex::new(".*")?,
3677 Some(path) => Regex::new(path.to_string().as_str())?,
3678 };
3679 Ok(Self {
3680 selector: ScopeSelectorDef {
3681 path,
3682 name: "Route".to_string(),
3683 },
3684 })
3685 }
3686
3687 pub fn from<I: ToString>(selector: LexScopeSelector<I>) -> Result<Self, SpaceErr> {
3688 if selector.name.to_string().as_str() != "Route" {
3689 return Err(SpaceErr::server_error("expected Route"));
3690 }
3691 let path = match selector.path {
3692 None => None,
3693 Some(path) => Some(path.to_string()),
3694 };
3695
3696 Ok(RouteScopeSelector::new(path)?)
3697 }
3698 }
3699
3700 impl Deref for RouteScopeSelector {
3701 type Target = ScopeSelectorDef<String, Regex>;
3702
3703 fn deref(&self) -> &Self::Target {
3704 &self.selector
3705 }
3706 }
3707
3708 #[derive(Clone)]
3709 pub struct ScopeSelectorDef<N, P> {
3710 pub name: N,
3711 pub path: P,
3712 }
3713
3714 impl ValueMatcher<DirectedWave> for RouteScopeSelector {
3715 fn is_match(&self, directed: &DirectedWave) -> Result<(), ()> {
3716 if self.name.as_str() != "Route" {
3717 return Err(());
3718 }
3719 match self.selector.path.is_match(&directed.core().uri.path()) {
3720 true => Ok(()),
3721 false => Err(()),
3722 }
3723 }
3724 }
3725
3726 impl ValueMatcher<SingularDirectedWave> for RouteScopeSelector {
3727 fn is_match(&self, directed: &SingularDirectedWave) -> Result<(), ()> {
3728 if self.name.as_str() != "Route" {
3729 return Err(());
3730 }
3731 match self.selector.path.is_match(&directed.core().uri.path()) {
3732 true => Ok(()),
3733 false => Err(()),
3734 }
3735 }
3736 }
3737
3738 impl ValueMatcher<DirectedWave> for MessageScopeSelector {
3739 fn is_match(&self, directed: &DirectedWave) -> Result<(), ()> {
3740 self.name.is_match(&directed.core().method.kind())?;
3741 match self.path.is_match(&directed.core().uri.path()) {
3742 true => Ok(()),
3743 false => Err(()),
3744 }
3745 }
3746 }
3747
3748 impl ValueMatcher<SingularDirectedWave> for MessageScopeSelector {
3749 fn is_match(&self, directed: &SingularDirectedWave) -> Result<(), ()> {
3750 self.name.is_match(&directed.core().method.kind())?;
3751 match self.path.is_match(&directed.core().uri.path()) {
3752 true => Ok(()),
3753 false => Err(()),
3754 }
3755 }
3756 }
3757
3758 fn default_path<I: ToString>(path: Option<I>) -> Result<Regex, SpaceErr> {
3759 match path {
3760 None => Ok(Regex::new(".*")?),
3761 Some(path) => Ok(Regex::new(path.to_string().as_str())?),
3762 }
3763 }
3764 impl WaveScope {
3765 pub fn from_scope<I: Span>(scope: LexParentScope<I>) -> Result<Self, SpaceErr> {
3766 let selector = MessageScopeSelectorAndFilters::from_selector(scope.selector)?;
3767 let mut block = vec![];
3768
3769 for scope in scope.block.into_iter() {
3770 let method = MethodScope::from_scope(&selector.selector.name, scope)?;
3771 block.push(method);
3772 }
3773
3774 Ok(Self { selector, block })
3775 }
3776
3777 pub fn select(&self, directed: &DirectedWave) -> Vec<&MethodScope> {
3778 let mut scopes = vec![];
3779 for scope in &self.block {
3780 if scope.selector.is_match(directed).is_ok() {
3781 scopes.push(scope);
3782 }
3783 }
3784 scopes
3785 }
3786 }
3787
3788 impl MessageScopeSelectorAndFilters {
3789 pub fn from_selector<I: Span>(selector: LexScopeSelector<I>) -> Result<Self, SpaceErr> {
3790 let filters = selector.filters.clone().to_scope_filters();
3791 let selector = MessageScopeSelector::from_selector(selector)?;
3792 Ok(Self { selector, filters })
3793 }
3794 }
3795
3796 impl RouteScopeSelectorAndFilters {
3797 pub fn from_selector<I: Span>(selector: LexScopeSelector<I>) -> Result<Self, SpaceErr> {
3798 let filters = selector.filters.clone().to_scope_filters();
3799 let selector = RouteScopeSelector::new(selector.path.clone())?;
3800 Ok(Self { selector, filters })
3801 }
3802 }
3803
3804 impl ValueMatcher<DirectedWave> for RouteScopeSelectorAndFilters {
3805 fn is_match(&self, request: &DirectedWave) -> Result<(), ()> {
3806 self.selector.is_match(request)
3808 }
3809 }
3810
3811 impl ValueMatcher<SingularDirectedWave> for RouteScopeSelectorAndFilters {
3812 fn is_match(&self, wave: &SingularDirectedWave) -> Result<(), ()> {
3813 self.selector.is_match(wave)
3815 }
3816 }
3817
3818 impl ValueMatcher<DirectedWave> for MessageScopeSelectorAndFilters {
3819 fn is_match(&self, request: &DirectedWave) -> Result<(), ()> {
3820 self.selector.is_match(request)
3822 }
3823 }
3824
3825 impl ValueMatcher<SingularDirectedWave> for MessageScopeSelectorAndFilters {
3826 fn is_match(&self, request: &SingularDirectedWave) -> Result<(), ()> {
3827 self.selector.is_match(request)
3829 }
3830 }
3831
3832 impl ValueMatcher<DirectedWave> for MethodScopeSelectorAndFilters {
3833 fn is_match(&self, directed: &DirectedWave) -> Result<(), ()> {
3834 self.selector.is_match(directed)
3836 }
3837 }
3838
3839 impl ValueMatcher<SingularDirectedWave> for MethodScopeSelectorAndFilters {
3840 fn is_match(&self, directed: &SingularDirectedWave) -> Result<(), ()> {
3841 self.selector.is_match(directed)
3843 }
3844 }
3845
3846 impl MethodScope {
3847 pub fn from_scope<I: Span>(
3848 parent: &ValuePattern<MethodKind>,
3849 scope: LexScope<I>,
3850 ) -> Result<Self, SpaceErr> {
3851 let selector = MethodScopeSelectorAndFilters::from_selector(parent, scope.selector)?;
3852 let block = result(pipeline(scope.block.content))?;
3853 Ok(Self { selector, block })
3854 }
3855 }
3856
3857 impl MessageScopeSelector {
3858 pub fn from_selector<I: Span>(selector: LexScopeSelector<I>) -> Result<Self, SpaceErr> {
3859 let kind = match result(value_pattern(method_kind)(selector.name.clone())) {
3860 Ok(kind) => kind,
3861 Err(_) => {
3862 return Err(ParseErrs::from_loc_span(
3863 format!(
3864 "unknown MessageKind: {} valid message kinds: Ext, Http, Cmd or *",
3865 selector.name.to_string()
3866 )
3867 .as_str(),
3868 "unknown message kind",
3869 selector.name,
3870 ));
3871 }
3872 };
3873
3874 Ok(Self {
3875 name: kind,
3876 path: default_path(selector.path)?,
3877 })
3878 }
3879 }
3880
3881 impl ValueMatcher<DirectedWave> for MethodScopeSelector {
3882 fn is_match(&self, directed: &DirectedWave) -> Result<(), ()> {
3883 self.name.is_match(&directed.core().method)?;
3884 match self.path.is_match(&directed.core().uri.path()) {
3885 true => Ok(()),
3886 false => Err(()),
3887 }
3888 }
3889 }
3890
3891 impl ValueMatcher<SingularDirectedWave> for MethodScopeSelector {
3892 fn is_match(&self, directed: &SingularDirectedWave) -> Result<(), ()> {
3893 self.name.is_match(&directed.core().method)?;
3894 match self.path.is_match(&directed.core().uri.path()) {
3895 true => Ok(()),
3896 false => Err(()),
3897 }
3898 }
3899 }
3900 impl MethodScopeSelectorAndFilters {
3901 pub fn from_selector<I: Span>(
3902 parent: &ValuePattern<MethodKind>,
3903 selector: LexScopeSelector<I>,
3904 ) -> Result<Self, SpaceErr> {
3905 let filters = selector.filters.clone().to_scope_filters();
3906 let selector = MethodScopeSelector::from_selector(parent, selector)?;
3907 Ok(Self { selector, filters })
3908 }
3909 }
3910
3911 impl MethodScopeSelector {
3912 pub fn from_selector<I: Span>(
3913 parent: &ValuePattern<MethodKind>,
3914 selector: LexScopeSelector<I>,
3915 ) -> Result<Self, SpaceErr> {
3916 let name = match parent {
3917 ValuePattern::Any => ValuePattern::Any,
3918 ValuePattern::None => ValuePattern::None,
3919 ValuePattern::Pattern(message_kind) => match message_kind {
3920 MethodKind::Hyp => {
3921 match result(value_pattern(wrapped_sys_method)(selector.name.clone())) {
3922 Ok(r) => r,
3923 Err(_) => {
3924 return Err(ParseErrs::from_loc_span(
3925 format!(
3926 "invalid Hyp method '{}'. Hyp should be CamelCase",
3927 selector.name.to_string()
3928 )
3929 .as_str(),
3930 "invalid Hyp",
3931 selector.name,
3932 ))
3933 }
3934 }
3935 }
3936 MethodKind::Cmd => {
3937 match result(value_pattern(wrapped_cmd_method)(selector.name.clone())) {
3938 Ok(r) => r,
3939 Err(_) => {
3940 return Err(ParseErrs::from_loc_span(
3941 format!(
3942 "invalid Cmd method '{}'. Cmd should be CamelCase",
3943 selector.name.to_string()
3944 )
3945 .as_str(),
3946 "invalid Cmd",
3947 selector.name,
3948 ))
3949 }
3950 }
3951 }
3952 MethodKind::Ext => {
3953 match result(value_pattern(wrapped_ext_method)(selector.name.clone())) {
3954 Ok(r) => r,
3955 Err(_) => {
3956 return Err(ParseErrs::from_loc_span(
3957 format!(
3958 "invalid Ext method '{}'. Ext should be CamelCase",
3959 selector.name.to_string()
3960 )
3961 .as_str(),
3962 "invalid Ext",
3963 selector.name,
3964 ))
3965 }
3966 }
3967 }
3968 MethodKind::Http => {
3969 match result(value_pattern( wrapped_http_method)(selector.name.clone())) {
3970 Ok(r) => r,
3971 Err(_) => {
3972 return Err(ParseErrs::from_loc_span(format!("invalid Http Pattern '{}'. Http should be camel case 'Get' and a valid Http method", selector.name.to_string()).as_str(), "invalid Http method", selector.name ))
3973 }
3974 }
3975 }
3976 },
3977 };
3978
3979 Ok(Self {
3980 name,
3981 path: default_path(selector.path)?,
3982 })
3983 }
3984 }
3985
3986 impl<N, P> ScopeSelectorDef<N, P> {
3987 pub fn new(name: N, path: P) -> Self {
3988 Self { name, path }
3989 }
3990 }
3991
3992 #[derive(Clone)]
3993 pub struct LexScopeSelector<I> {
3994 pub name: I,
3995 pub filters: ScopeFiltersDef<I>,
3996 pub children: Option<I>,
3997 pub path: Option<I>,
3998 }
3999
4000 impl<I: ToString> LexScopeSelector<I> {
4001 pub fn new(
4002 name: I,
4003 filters: ScopeFiltersDef<I>,
4004 path: Option<I>,
4005 children: Option<I>,
4006 ) -> Self {
4007 Self {
4008 name,
4009 filters,
4010 children,
4011 path,
4012 }
4013 }
4014 }
4015
4016 impl<I> LexScopeSelector<I> {
4017 pub fn has_children(&self) -> bool {
4018 self.children.is_some()
4019 }
4020 }
4021
4022 #[derive(Clone)]
4023 pub struct ScopeFiltersDef<I> {
4024 pub filters: Vec<ScopeFilterDef<I>>,
4025 }
4026
4027 impl Default for ScopeFilters {
4028 fn default() -> Self {
4029 Self { filters: vec![] }
4030 }
4031 }
4032
4033 impl<I> Deref for ScopeFiltersDef<I> {
4034 type Target = Vec<ScopeFilterDef<I>>;
4035
4036 fn deref(&self) -> &Self::Target {
4037 &self.filters
4038 }
4039 }
4040
4041 impl<I> ScopeFiltersDef<I> {
4042 pub fn is_empty(&self) -> bool {
4043 self.filters.is_empty()
4044 }
4045 }
4046
4047 impl<I: ToString> ScopeFiltersDef<I> {
4048 pub fn to_scope_filters(self) -> ScopeFilters {
4049 ScopeFilters {
4050 filters: self
4051 .filters
4052 .into_iter()
4053 .map(|f| f.to_scope_filter())
4054 .collect(),
4055 }
4056 }
4057
4058 pub fn len(&self) -> usize {
4059 self.filters.len()
4060 }
4061
4062 pub fn empty() -> Self {
4063 Self { filters: vec![] }
4064 }
4065 }
4066
4067 #[derive(Clone)]
4068 pub struct ScopeFilterDef<I> {
4069 pub name: I,
4070 pub args: Option<I>,
4071 }
4072
4073 impl<I: ToString> ScopeFilterDef<I> {
4074 pub fn to_scope_filter(self) -> ScopeFilter {
4075 ScopeFilter {
4076 name: self.name.to_string(),
4077 args: match self.args {
4078 None => None,
4079 Some(args) => Some(args.to_string()),
4080 },
4081 }
4082 }
4083 }
4084
4085 pub type RegexStr = String;
4086 pub type ScopeFilter = ScopeFilterDef<String>;
4087 pub type ScopeFilters = ScopeFiltersDef<String>;
4088 pub type LexBlock<I> = Block<I, ()>;
4089 pub type LexRootScope<I> = Scope<RootScopeSelector<I, Spanned<I, Version>>, Block<I, ()>, I>;
4090 pub type LexScope<I> = Scope<LexScopeSelector<I>, Block<I, ()>, I>;
4091 pub type LexParentScope<I> = Scope<LexScopeSelector<I>, Vec<LexScope<I>>, I>;
4092
4093 pub type PipelineSegmentCtx = PipelineSegmentDef<PointCtx>;
4095 pub type PipelineSegmentVar = PipelineSegmentDef<PointVar>;
4096
4097 #[derive(Debug, Clone)]
4098 pub struct PipelineSegmentDef<Pnt> {
4099 pub step: PipelineStepDef<Pnt>,
4100 pub stop: PipelineStopDef<Pnt>,
4101 }
4102
4103 impl ToResolved<PipelineSegment> for PipelineSegmentVar {
4104 fn to_resolved(self, env: &Env) -> Result<PipelineSegment, SpaceErr> {
4105 let rtn: PipelineSegmentCtx = self.to_resolved(env)?;
4106 rtn.to_resolved(env)
4107 }
4108 }
4109
4110 impl ToResolved<PipelineSegment> for PipelineSegmentCtx {
4111 fn to_resolved(self, env: &Env) -> Result<PipelineSegment, SpaceErr> {
4112 Ok(PipelineSegment {
4113 step: self.step.to_resolved(env)?,
4114 stop: self.stop.to_resolved(env)?,
4115 })
4116 }
4117 }
4118
4119 impl ToResolved<PipelineSegmentCtx> for PipelineSegmentVar {
4120 fn to_resolved(self, env: &Env) -> Result<PipelineSegmentCtx, SpaceErr> {
4121 Ok(PipelineSegmentCtx {
4122 step: self.step.to_resolved(env)?,
4123 stop: self.stop.to_resolved(env)?,
4124 })
4125 }
4126 }
4127
4128 pub type PipelineSegment = PipelineSegmentDef<Point>;
4160 pub type RouteScope = ScopeDef<RouteScopeSelectorAndFilters, Vec<WaveScope>>;
4161 pub type WaveScope = ScopeDef<MessageScopeSelectorAndFilters, Vec<MethodScope>>;
4162 pub type MethodScope = ScopeDef<MethodScopeSelectorAndFilters, PipelineVar>;
4163 pub type MessageScopeSelector = ScopeSelectorDef<ValuePattern<MethodKind>, Regex>;
4165 pub type MethodScopeSelector = ScopeSelectorDef<ValuePattern<Method>, Regex>;
4166 pub type RouteScopeSelectorAndFilters = ScopeSelectorAndFiltersDef<RouteScopeSelector, String>;
4167 pub type MessageScopeSelectorAndFilters =
4168 ScopeSelectorAndFiltersDef<MessageScopeSelector, String>;
4169 pub type MethodScopeSelectorAndFilters =
4170 ScopeSelectorAndFiltersDef<MethodScopeSelector, String>;
4171
4172 pub type LexScopeSelectorAndFilters<I> = ScopeSelectorAndFiltersDef<LexScopeSelector<I>, I>;
4177 impl<I: Span> TryFrom<LexParentScope<I>> for RouteScope {
4180 type Error = SpaceErr;
4181
4182 fn try_from(scope: LexParentScope<I>) -> Result<Self, Self::Error> {
4183 let mut errs = vec![];
4184 let mut message_scopes = vec![];
4185 let route_selector = RouteScopeSelectorAndFilters::from_selector(scope.selector)?;
4186 for message_scope in scope.block {
4187 match lex_child_scopes(message_scope) {
4188 Ok(message_scope) => match WaveScope::from_scope(message_scope) {
4189 Ok(message_scope) => message_scopes.push(message_scope),
4190 Err(err) => errs.push(err),
4191 },
4192 Err(err) => {
4193 errs.push(err);
4194 }
4195 }
4196 }
4197 if errs.is_empty() {
4198 Ok(RouteScope {
4199 selector: route_selector,
4200 block: message_scopes,
4201 })
4202 } else {
4203 Err(ParseErrs::fold(errs).into())
4204 }
4205 }
4206 }
4207
4208 pub type Pipeline = PipelineDef<PipelineSegment>;
4238 pub type PipelineCtx = PipelineDef<PipelineSegmentCtx>;
4239 pub type PipelineVar = PipelineDef<PipelineSegmentVar>;
4240
4241 impl ToResolved<Pipeline> for PipelineCtx {
4242 fn to_resolved(self, env: &Env) -> Result<Pipeline, SpaceErr> {
4243 let mut segments = vec![];
4244 for segment in self.segments.into_iter() {
4245 segments.push(segment.to_resolved(env)?);
4246 }
4247
4248 Ok(Pipeline { segments })
4249 }
4250 }
4251
4252 impl ToResolved<PipelineCtx> for PipelineVar {
4253 fn to_resolved(self, env: &Env) -> Result<PipelineCtx, SpaceErr> {
4254 let mut segments = vec![];
4255 for segment in self.segments.into_iter() {
4256 segments.push(segment.to_resolved(env)?);
4257 }
4258
4259 Ok(PipelineCtx { segments })
4260 }
4261 }
4262
4263 #[derive(Debug, Clone, Serialize, Deserialize)]
4285 pub struct PipelineDef<S> {
4286 pub segments: Vec<S>,
4287 }
4288
4289 impl<S> PipelineDef<S> {
4290 pub fn new() -> Self {
4291 Self { segments: vec![] }
4292 }
4293 }
4294
4295 impl<S> Deref for PipelineDef<S> {
4296 type Target = Vec<S>;
4297
4298 fn deref(&self) -> &Self::Target {
4299 &self.segments
4300 }
4301 }
4302
4303 impl<S> DerefMut for PipelineDef<S> {
4304 fn deref_mut(&mut self) -> &mut Self::Target {
4305 &mut self.segments
4306 }
4307 }
4308
4309 impl<S> PipelineDef<S> {
4310 pub fn consume(&mut self) -> Option<S> {
4311 if self.segments.is_empty() {
4312 None
4313 } else {
4314 Some(self.segments.remove(0))
4315 }
4316 }
4317 }
4318
4319 #[derive(Clone)]
4394 pub enum MechtronScope {
4395 WasmScope(Vec<Assignment>),
4396 }
4397
4398 #[derive(Clone)]
4399 pub enum BindScope {
4400 RequestScope(RouteScope),
4401 }
4402
4403 #[derive(Debug, Clone)]
4404 pub struct ScopeDef<S, B> {
4405 pub selector: S,
4406 pub block: B,
4407 }
4408
4409 #[derive(Clone)]
4410 pub enum BindScopeKind {
4411 Pipelines,
4412 }
4413
4414 #[derive(Clone)]
4415 pub enum BuiltInFilter {
4416 Auth,
4417 NoAuth,
4418 }
4419
4420 #[derive(Clone)]
4421 pub struct Scope<S, B, P>
4422 where
4423 S: Clone,
4424 {
4425 pub selector: S,
4426 pub pipeline_step: Option<P>,
4427 pub block: B,
4428 }
4429
4430 impl<S, B, P> Scope<S, B, P>
4431 where
4432 S: Clone,
4433 {
4434 pub fn new(selector: S, block: B) -> Self {
4435 Self {
4436 selector,
4437 block,
4438 pipeline_step: None,
4439 }
4440 }
4441
4442 pub fn new_with_pipeline_step(selector: S, block: B, pipeline_step: Option<P>) -> Self {
4443 Self {
4444 selector,
4445 block,
4446 pipeline_step,
4447 }
4448 }
4449 }
4450
4451 impl<S, FromBlock, P> Scope<S, FromBlock, P>
4452 where
4453 S: Clone,
4454 {
4455 pub fn upgrade<ToBlock>(self, block: ToBlock) -> Scope<S, ToBlock, P> {
4456 Scope {
4457 selector: self.selector,
4458 block,
4459 pipeline_step: self.pipeline_step,
4460 }
4461 }
4462 }
4463
4464 #[derive(Clone)]
4465 pub struct Block<I, D> {
4466 pub kind: BlockKind,
4467 pub content: I,
4468 pub data: D,
4469 }
4470
4471 impl<I> Block<I, ()> {
4472 pub fn parse(kind: BlockKind, content: I) -> Block<I, ()> {
4473 Block {
4474 kind,
4475 content,
4476 data: (),
4477 }
4478 }
4479 }
4480
4481 #[derive(Debug, Copy, Clone, strum_macros::Display, Eq, PartialEq)]
4482 pub enum BlockKind {
4483 Nested(NestedBlockKind),
4484 Terminated(TerminatedBlockKind),
4485 Delimited(DelimitedBlockKind),
4486 Partial,
4487 }
4488
4489 #[derive(Debug, Copy, Clone, strum_macros::Display, Eq, PartialEq)]
4490 pub enum TerminatedBlockKind {
4491 Semicolon,
4492 }
4493
4494 impl TerminatedBlockKind {
4495 pub fn tag(&self) -> &'static str {
4496 match self {
4497 TerminatedBlockKind::Semicolon => ";",
4498 }
4499 }
4500
4501 pub fn as_char(&self) -> char {
4502 match self {
4503 TerminatedBlockKind::Semicolon => ';',
4504 }
4505 }
4506 }
4507
4508 #[derive(
4509 Debug, Copy, Clone, strum_macros::Display, strum_macros::EnumString, Eq, PartialEq,
4510 )]
4511 pub enum DelimitedBlockKind {
4512 SingleQuotes,
4513 DoubleQuotes,
4514 }
4515
4516 impl DelimitedBlockKind {
4517 pub fn delim(&self) -> &'static str {
4518 match self {
4519 DelimitedBlockKind::SingleQuotes => "'",
4520 DelimitedBlockKind::DoubleQuotes => "\"",
4521 }
4522 }
4523
4524 pub fn escaped(&self) -> &'static str {
4525 match self {
4526 DelimitedBlockKind::SingleQuotes => "\'",
4527 DelimitedBlockKind::DoubleQuotes => "\"",
4528 }
4529 }
4530
4531 pub fn context(&self) -> &'static str {
4532 match self {
4533 DelimitedBlockKind::SingleQuotes => "single:quotes:block",
4534 DelimitedBlockKind::DoubleQuotes => "double:quotes:block",
4535 }
4536 }
4537
4538 pub fn missing_close_context(&self) -> &'static str {
4539 match self {
4540 DelimitedBlockKind::SingleQuotes => "single:quotes:block:missing-close",
4541 DelimitedBlockKind::DoubleQuotes => "double:quotes:block:missing-close",
4542 }
4543 }
4544 }
4545
4546 #[derive(
4547 Debug, Copy, Clone, strum_macros::Display, strum_macros::EnumString, Eq, PartialEq,
4548 )]
4549 pub enum NestedBlockKind {
4550 Curly,
4551 Parens,
4552 Square,
4553 Angle,
4554 }
4555
4556 impl NestedBlockKind {
4557 pub fn is_block_terminator(c: char) -> bool {
4558 match c {
4559 '}' => true,
4560 ')' => true,
4561 ']' => true,
4562 '>' => true,
4563 _ => false,
4564 }
4565 }
4566
4567 pub fn error_message<I: Span>(span: &I, context: &str) -> Result<&'static str, ()> {
4568 if Self::Curly.open_context() == context {
4569 Ok("expecting '{' (open scope block)")
4570 } else if Self::Parens.open_context() == context {
4571 Ok("expecting '(' (open scope block)")
4572 } else if Self::Angle.open_context() == context {
4573 Ok("expecting '<' (open scope block)")
4574 } else if Self::Square.open_context() == context {
4575 Ok("expecting '[' (open scope block)")
4576 } else if Self::Curly.close_context() == context {
4577 Ok("expecting '}' (close scope block)")
4578 } else if Self::Parens.close_context() == context {
4579 Ok("expecting ')' (close scope block)")
4580 } else if Self::Angle.close_context() == context {
4581 Ok("expecting '>' (close scope block)")
4582 } else if Self::Square.close_context() == context {
4583 Ok("expecting ']' (close scope block)")
4584 } else if Self::Curly.unpaired_closing_scope() == context {
4585 Ok("closing scope without an opening scope")
4586 } else if Self::Parens.unpaired_closing_scope() == context {
4587 Ok("closing scope without an opening scope")
4588 } else if Self::Angle.unpaired_closing_scope() == context {
4589 Ok("closing scope without an opening scope")
4590 } else if Self::Square.unpaired_closing_scope() == context {
4591 Ok("closing scope without an opening scope")
4592 } else {
4593 Err(())
4594 }
4595 }
4596
4597 pub fn context(&self) -> &'static str {
4598 match self {
4599 NestedBlockKind::Curly => "block:{}",
4600 NestedBlockKind::Parens => "block:()",
4601 NestedBlockKind::Square => "block:[]",
4602 NestedBlockKind::Angle => "block:<>",
4603 }
4604 }
4605
4606 pub fn open_context(&self) -> &'static str {
4607 match self {
4608 NestedBlockKind::Curly => "block:open:{",
4609 NestedBlockKind::Parens => "block:open:(",
4610 NestedBlockKind::Square => "block:open:[",
4611 NestedBlockKind::Angle => "block:open:<",
4612 }
4613 }
4614
4615 pub fn close_context(&self) -> &'static str {
4616 match self {
4617 NestedBlockKind::Curly => "block:close:}",
4618 NestedBlockKind::Parens => "block:close:)",
4619 NestedBlockKind::Square => "block:close:]",
4620 NestedBlockKind::Angle => "block:close:>",
4621 }
4622 }
4623
4624 pub fn unpaired_closing_scope(&self) -> &'static str {
4625 match self {
4626 NestedBlockKind::Curly => "block:close-before-open:}",
4627 NestedBlockKind::Parens => "block:close-before-open:)",
4628 NestedBlockKind::Square => "block:close-before-open:]",
4629 NestedBlockKind::Angle => "block:close-before-open:>",
4630 }
4631 }
4632
4633 pub fn open(&self) -> &'static str {
4634 match self {
4635 NestedBlockKind::Curly => "{",
4636 NestedBlockKind::Parens => "(",
4637 NestedBlockKind::Square => "[",
4638 NestedBlockKind::Angle => "<",
4639 }
4640 }
4641
4642 pub fn close(&self) -> &'static str {
4643 match self {
4644 NestedBlockKind::Curly => "}",
4645 NestedBlockKind::Parens => ")",
4646 NestedBlockKind::Square => "]",
4647 NestedBlockKind::Angle => ">",
4648 }
4649 }
4650
4651 pub fn open_as_char(&self) -> char {
4652 match self {
4653 NestedBlockKind::Curly => '{',
4654 NestedBlockKind::Parens => '(',
4655 NestedBlockKind::Square => '[',
4656 NestedBlockKind::Angle => '<',
4657 }
4658 }
4659
4660 pub fn close_as_char(&self) -> char {
4661 match self {
4662 NestedBlockKind::Curly => '}',
4663 NestedBlockKind::Parens => ')',
4664 NestedBlockKind::Square => ']',
4665 NestedBlockKind::Angle => '>',
4666 }
4667 }
4668 }
4669
4670 pub enum TextType<I> {
4671 Comment(I),
4672 NoComment(I),
4673 }
4674
4675 impl<I: ToString> ToString for TextType<I> {
4676 fn to_string(&self) -> String {
4677 match self {
4678 TextType::Comment(i) => i.to_string(),
4679 TextType::NoComment(i) => i.to_string(),
4680 }
4681 }
4682 }
4683
4684 #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
4685 pub enum Chunk<I> {
4686 Var(I),
4687 Text(I),
4688 }
4689 impl<I> Chunk<I>
4690 where
4691 I: Span,
4692 {
4693 pub fn stringify(self) -> Chunk<Tw<String>> {
4694 match self {
4695 Chunk::Var(var) => Chunk::Var(Tw::new(var.clone(), var.to_string())),
4696 Chunk::Text(text) => Chunk::Text(Tw::new(text.clone(), text.to_string())),
4697 }
4698 }
4699 }
4700
4701 impl<I> Chunk<I> {
4702 pub fn span(&self) -> &I {
4703 match self {
4704 Chunk::Var(var) => var,
4705 Chunk::Text(text) => text,
4706 }
4707 }
4708 }
4709
4710 impl<I: ToString> Chunk<I> {
4711 pub fn len(&self) -> usize {
4712 match self {
4713 Chunk::Var(var) => {
4714 var.to_string().len() + 3
4716 }
4717 Chunk::Text(text) => text.to_string().len(),
4718 }
4719 }
4720 }
4721
4722 #[derive(Clone)]
4723 pub enum Var<O, P>
4724 where
4725 P: VarParser<O>,
4726 {
4727 Val(O),
4728 Var { name: String, parser: P },
4729 }
4730
4731 pub trait VarParser<O> {
4732 fn parse<I: Span>(input: I) -> Result<O, SpaceErr>;
4733 }
4734
4735 #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
4736 pub struct Subst<I> {
4737 pub chunks: Vec<Chunk<I>>,
4738 pub trace: Trace,
4739 }
4740
4741 impl Subst<Tw<String>> {
4742 pub fn new(path: &str) -> Result<Self, SpaceErr> {
4743 let path = result(crate::parse::subst_path(new_span(path)))?;
4744 Ok(path.stringify())
4745 }
4746 }
4747
4748 impl<I> Subst<I>
4749 where
4750 I: Span,
4751 {
4752 pub fn stringify(self) -> Subst<Tw<String>> {
4753 let chunks: Vec<Chunk<Tw<String>>> =
4754 self.chunks.into_iter().map(|c| c.stringify()).collect();
4755 Subst {
4756 chunks,
4757 trace: self.trace,
4758 }
4759 }
4760 }
4761
4762 impl<I> ToString for Subst<I>
4763 where
4764 I: ToString,
4765 {
4766 fn to_string(&self) -> String {
4767 let mut rtn = String::new();
4768 for chunk in &self.chunks {
4769 match chunk {
4770 Chunk::Var(var) => {
4771 rtn.push_str(format!("${{{}}}", var.to_string()).as_str());
4772 }
4773 Chunk::Text(text) => {
4774 rtn.push_str(text.to_string().as_str());
4775 }
4776 }
4777 }
4778 rtn
4779 }
4780 }
4781
4782 impl ToResolved<String> for Subst<Tw<String>> {
4783 fn to_resolved(self, env: &Env) -> Result<String, SpaceErr> {
4784 let mut rtn = String::new();
4785 let mut errs = vec![];
4786 for chunk in self.chunks {
4787 match chunk {
4788 Chunk::Var(var) => match env.val(var.to_string().as_str()) {
4789 Ok(val) => {
4790 let val: String = val.clone().try_into()?;
4791 rtn.push_str(val.as_str());
4792 }
4793 Err(err) => {
4794 errs.push(ParseErrs::from_range(
4795 format!("could not find variable: {}", var.to_string()).as_str(),
4796 "not found",
4797 var.trace.range,
4798 var.trace.extra,
4799 ));
4800 }
4801 },
4802 Chunk::Text(text) => {
4803 rtn.push_str(text.to_string().as_str());
4804 }
4805 }
4806 }
4807
4808 if errs.is_empty() {
4809 Ok(rtn)
4810 } else {
4811 let errs = ParseErrs::fold(errs);
4812 Err(errs.into())
4813 }
4814 }
4815 }
4816}
4817
4818pub mod error {
4819 use core::str::FromStr;
4820 use std::collections::HashMap;
4821 use std::sync::Arc;
4822 use nom::branch::alt;
4825 use nom::bytes::complete::tag;
4826 use nom::character::complete::{
4827 alpha1, alphanumeric0, alphanumeric1, digit1, multispace0, multispace1, satisfy, space1,
4828 };
4829 use nom::combinator::{all_consuming, cut, fail, not, opt, peek, recognize, value};
4830 use nom::error::{context, ContextError, ErrorKind, ParseError};
4831 use nom::multi::{many0, many1, separated_list0};
4832 use nom::sequence::{delimited, pair, preceded, terminated, tuple};
4833 use nom::{
4834 AsChar, Compare, Err, InputLength, InputTake, InputTakeAtPosition, IResult, Parser, Slice,
4835 };
4836 use nom_supreme::error::{BaseErrorKind, ErrorTree, StackContext};
4837 use regex::{Error, Regex};
4838
4839 use cosmic_nom::{len, new_span, Res, Span, span_with_extra, trim, tw};
4840
4841 use crate::command::direct::CmdKind;
4842 use crate::command::CommandVar;
4843 use crate::config::bind::{PipelineStepVar, PipelineStopVar, RouteSelector, WaveDirection};
4844 use crate::err::report::{Label, Report, ReportKind};
4845 use crate::err::{ParseErrs, SpaceErr};
4846 use crate::kind::KindParts;
4847 use crate::loc::{Layer, StarKey, Topic, VarVal, Version};
4848 use crate::parse::model::{
4849 BindScope, BindScopeKind, BlockKind, Chunk, DelimitedBlockKind, LexScope, NestedBlockKind,
4850 PipelineSegmentVar, PipelineVar, RouteScope, Spanned, Subst, TextType,
4851 };
4852 use crate::parse::{
4853 any_block, any_soround_lex_block, camel_case, camel_case_chars,
4854 camel_case_to_string_matcher, CamelCase, domain, file_chars, filepath_chars, get,
4855 lex_child_scopes, lex_root_scope, lex_route_selector, lex_scopes, lowercase_alphanumeric,
4856 method_kind, nospace1, parse_uuid, point_segment_chars, point_var, rec_version, select, set,
4857 skewer, skewer_case, skewer_chars, subst_path, SubstParser, unwrap_block,
4858 variable_name, version_chars, version_req_chars,
4859 };
4860 use crate::particle::PointKindVar;
4861 use crate::selector::{
4862 ExactPointSeg, Hop, KindBaseSelector, KindSelector, LabeledPrimitiveTypeDef,
4863 MapEntryPattern, MapEntryPatternVar, Pattern, PatternBlockVar, PayloadBlockVar,
4864 PayloadType2Def, PointSegSelector, SelectorDef, SpecificSelector, SubKindSelector,
4865 UploadBlock, VersionReq,
4866 };
4867 use crate::substance::{
4868 CallKind, CallVar, CallWithConfigVar, ExtCall, HttpCall, ListPattern, MapPatternVar,
4869 NumRange, SubstanceFormat, SubstanceKind, SubstancePattern, SubstancePatternVar,
4870 SubstanceTypePatternDef, SubstanceTypePatternVar,
4871 };
4872 use crate::util::{HttpMethodPattern, StringMatcher, ToResolved, ValuePattern};
4873 use crate::wave::core::cmd::CmdMethod;
4874 use crate::wave::core::ext::ExtMethod;
4875 use crate::wave::core::http2::HttpMethod;
4876 use crate::wave::core::hyp::HypMethod;
4877 use crate::wave::core::{Method, MethodKind, MethodPattern};
4878 use crate::{
4879 ArtifactSubKind, BaseKind, BindConfig, Document, FileSubKind, Kind, Selector, Specific,
4880 StarSub, Strategy, Surface,
4881 };
4882 use crate::point::{PointSeg, PointVar};
4883
4884 pub fn result<I: Span, R>(result: Result<(I, R), Err<ErrorTree<I>>>) -> Result<R, SpaceErr> {
4885 match result {
4886 Ok((_, e)) => Ok(e),
4887 Err(err) => Err(find_parse_err(&err)),
4888 }
4889 }
4890
4891 fn create_err_report<I: Span>(context: &str, loc: I) -> SpaceErr {
4907 let mut builder = Report::build(ReportKind::Error, (), 23);
4908
4909 match NestedBlockKind::error_message(&loc, context) {
4910 Ok(message) => {
4911 let builder = builder.with_message(message).with_label(
4912 Label::new(loc.location_offset()..loc.location_offset()).with_message(message),
4913 );
4914 return ParseErrs::from_report(builder.finish(), loc.extra()).into();
4915 }
4916 Err(_) => {}
4917 }
4918
4919 let builder = match context {
4920 "var" => {
4921 let f = |input| {preceded(tag("$"),many0(alt((tag("{"),alphanumeric1,tag("-"),tag("_"),multispace1))))(input)};
4922 let len = len(f)(loc.clone())+1;
4923 builder.with_message("Variables should be lowercase skewer with a leading alphabet character and surrounded by ${} i.e.:'${var-name}' ").with_label(Label::new(loc.location_offset()..loc.location_offset()+len).with_message("Bad Variable Substitution"))
4924 },
4925 "assignment:plus" => {
4926 builder.with_message("Expecting a preceding '+' (create variable operator)").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expected '+'"))
4927 }
4928 "assignment:equals" => {
4929 builder.with_message("Expecting a preceding '=' for assignment").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expecting '='"))
4930 }
4931 "assignment:value" => {
4932 builder.with_message("Expecting a value").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expecting value"))
4933 }
4934 "capture-path" => {
4935 builder.with_message("Invalid capture path. Legal characters are filesystem characters plus captures $(var=.*) i.e. /users/$(user=.*)").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Illegal capture path"))
4936
4937 }
4938 "point" => {
4939 builder.with_message("Invalid Point").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid Point"))
4940 },
4941
4942 "resolver-not-available" => {
4943 builder.with_message("Var & Working Point resolution are not available in this context").with_label(Label::new(loc.location_offset()..loc.location_offset()+loc.len()).with_message("resolution not available"))
4944 }
4945 "var-resolver-not-available" => {
4946 builder.with_message("Variable resolution is not available in this context").with_label(Label::new(loc.location_offset()..loc.location_offset()+loc.len()).with_message("var resolution not available"))
4947 }
4948 "ctx-resolver-not-available" => {
4949 builder.with_message("WorkingPoint resolution is not available in this context").with_label(Label::new(loc.location_offset()..loc.location_offset()+loc.len()).with_message("working point resolution not available"))
4950 }
4951
4952 "regex" => {
4953 let span = result(nospace1(loc.clone()));
4954 match span {
4955 Ok(span) => {
4956 match Regex::new(loc.to_string().as_str()) {
4957 Ok(_) => {
4958 builder.with_message("internal parse error: regex error in this expression")
4959 }
4960 Err(err) => {
4961 match err {
4962 Error::Syntax(syntax) => {
4963 builder.with_message(format!("Regex Syntax Error: '{}'",syntax)).with_label(Label::new(span.location_offset()..span.location_offset()+span.len()).with_message("regex syntax error"))
4964 }
4965 Error::CompiledTooBig(size) => {
4966 builder.with_message("Regex compiled too big").with_label(Label::new(span.location_offset()..span.location_offset()+span.len()).with_message("regex compiled too big"))
4967 }
4968 _ => {
4969
4970 builder.with_message("Regex is nonexhaustive").with_label(Label::new(span.location_offset()..span.location_offset()+span.len()).with_message("non-exhaustive regex"))
4971
4972 }
4973 }
4974 }
4975 }
4976 }
4977 Err(_) => {
4978 builder.with_message("internal parse error: could not identify regex")
4979 }
4980 }
4981 },
4982 "expect-camel-case" => { builder.with_message("expecting a CamelCase expression").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expecting CamelCase"))},
4983 "expect-skewer-case" => { builder.with_message("expecting a skewer-case expression").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expecting skewer-case"))},
4984 "parsed-scopes" => { builder.with_message("expecting a properly formed scope").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("not a scope"))},
4985 "scope" => { builder.with_message("expecting a properly formed scope").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("not a scope"))},
4986 "root-scope:block" => { builder.with_message("expecting root scope block {}").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Scope Block"))},
4987 "pipeline:stop:expecting" =>{ builder.with_message("expecting a pipeline stop: point, call, or return ('&')").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Pipeline Stop"))},
4988 "pipeline:step" =>{ builder.with_message("expecting a pipeline step ('->', '=>', '-[ Bin ]->', etc...)").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Pipeline Step"))},
4989 "pipeline:step:entry" =>{ builder.with_message("expecting a pipeline step entry ('-' or '=') to form a pipeline step i.e. '->' or '=>'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Pipeline Entry"))},
4990 "pipeline:step:exit" =>{ builder.with_message("expecting a pipeline step exit i.e. '->' or '=>'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Pipeline Exit"))},
4991 "pipeline:step:payload" =>{ builder.with_message("Invalid payload filter").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("invalid payload filter"))},
4992 "scope:expect-space-after-pipeline-step" =>{ builder.with_message("expecting a space after selection pipeline step (->)").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Space"))},
4993 "scope-selector-name:expect-alphanumeric-leading" => { builder.with_message("expecting a valid scope selector name starting with an alphabetic character").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Expecting Alpha Char"))},
4994 "scope-selector-name:expect-termination" => { builder.with_message("expecting scope selector to be followed by a space, a filter declaration: '(filter)->' or a sub scope selector: '<SubScope> or subscope terminator '>' '").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Bad Scope Selector Termination"))},
4995 "scope-selector-version-closing-tag" =>{ builder.with_message("expecting a closing parenthesis for the root version declaration (no spaces allowed) -> i.e. Bind(version=1.0.0)->").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("missing closing parenthesis"))}
4996 "scope-selector-version-missing-kazing"=> { builder.with_message("The version declaration needs a little style. Try adding a '->' to it. Make sure there are no spaces between the parenthesis and the -> i.e. Bind(version=1.0.0)->").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("missing stylish arrow"))}
4997 "scope-selector-version" => { builder.with_message("Root config selector requires a version declaration with NO SPACES between the name and the version filter example: Bind(version=1.0.0)->").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("bad version declaration"))}
4998 "scope-selector-name" => { builder.with_message("Expecting an alphanumeric scope selector name. example: Pipeline").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expecting scope selector"))}
4999 "root-scope-selector-name" => { builder.with_message("Expecting an alphanumeric root scope selector name and version. example: Bind(version=1.0.0)->").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("expecting scope selector"))}
5000 "consume" => { builder.with_message("Expected to be able to consume the entire String")}
5001 "point:space_segment:dot_dupes" => { builder.with_message("Space Segment cannot have consecutive dots i.e. '..'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Consecutive dots not allowed"))}
5002 "point:version:root_not_trailing" =>{ builder.with_message("Root filesystem is the only segment allowed to follow a bundle version i.e. 'space:base:2.0.0-version:/dir/somefile.txt'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Only root file segment ':/' allowed here"))}
5003 "point:space_segment_leading" => {builder.with_message("The leading character of a Space segment must be a lowercase letter").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid Leading Character"))}
5004 "point:space_segment" => {builder.with_message("A Point Space Segment must be all lowercase, alphanumeric with dashes and dots. It follows Host and Domain name rules i.e. 'localhost', 'mechtron.io'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid Space Segment"))}
5005 "point:bad_leading" => {builder.with_message("The leading character must be a lowercase letter (for Base Segments) or a digit (for Version Segments)").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid Leading Character"))}
5006 "point:base_segment" => {builder.with_message("A Point Base Segment must be 'skewer-case': all lowercase alphanumeric with dashes. The leading character must be a letter.").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid Base Segment Character"))}
5007 "point:dir_pop" => {builder.with_message("A Point Directory Pop '..'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Something is Wrong"))}
5008 "point:dir_segment" => {builder.with_message("A Point Dir Segment follows legal filesystem characters and must end in a '/'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Illegal Character"))}
5009 "point:root_filesystem_segment" => {builder.with_message("Root FileSystem ':/'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Illegal Character"))}
5010 "point:file_segment" => {builder.with_message("A Point File Segment follows legal filesystem characters").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Illegal Character"))}
5011 "point:file_or_directory"=> {builder.with_message("A Point File Segment (Files & Directories) follows legal filesystem characters").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Illegal Character"))}
5012 "point:version_segment" => {builder.with_message("A Version Segment allows all legal SemVer characters").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Illegal Character"))}
5013 "filter-name" => {builder.with_message("Filter name must be skewer case with leading character").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid filter name"))}
5014 "kind-base" => {builder.with_message("Invalid Base Kind").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Base Kind not recognized"))}
5015 "command" => {builder.with_message("Unrecognized Command").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Invalid"))}
5016 "parsed-scope-selector-kazing" => {builder.with_message("Selector needs some style with the '->' operator either right after the Selector i.e.: 'Pipeline ->' or as part of the filter declaration i.e. 'Pipeline(auth)->'").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Missing or Invalid Kazing Operator( -> )"))}
5017 "variable" => {
5018 builder.with_message("variable name must be alphanumeric lowercase, dashes and dots. Variables are preceded by the '$' operator and must be sorounded by curly brackets ${env.valid-variable-name}")
5019 },
5020 "variable:close" => {
5021 builder.with_message("variable name must be alphanumeric lowercase, dashes and dots. Variables are preceded by the '$' operator and must be sorounded by curly brackets with no spaces ${env.valid-variable-name}").with_label(Label::new(loc.location_offset()..loc.location_offset()).with_message("Bad Variable Substitution"))
5022 },
5023
5024 "child_perms" => {
5025 builder.with_message("expecting child permissions form csd (Create, Select, Delete) uppercase indicates set permission (CSD==full permission, csd==no permission)")
5026 },
5027 "particle_perms" => {
5028 builder.with_message("expecting particle permissions form rwx (Read, Write, Execute) uppercase indicates set permission (RWX==full permission, rwx==no permission)")
5029 },
5030 "permissions" => {
5031 builder.with_message("expecting permissions form 'csd-rwx' (Create,Select,Delete)-(Read,Write,Execute) uppercase indicates set permission (CSD-RWX==full permission, csd-rwx==no permission)")
5032 }
5033 "permissions_mask" => {
5034 builder.with_message("expecting permissions mask symbol '+' for 'Or' mask and '&' for 'And' mask. Example: &csd-RwX removes ----R-X from current permission")
5035 }
5036 "privilege" => {
5037 builder.with_message("privilege name must be '*' for 'full' privileges or an alphanumeric lowercase, dashes and colons i.e. 'props:email:read'")
5038 },
5039 "access_grant:perm" => {
5040 builder.with_message("expecting permissions mask symbol '+' for 'Or' mask and '&' for 'And' mask. Example: &csd-RwX removes ----R-X from current permission")
5041 },
5042 "access_grant:priv" => {
5043 builder.with_message("privilege name must be '*' for 'full' privileges or an alphanumeric lowercase, dashes and colons i.e. 'props:email:read'")
5044 },
5045 "access_grant:on" => {
5046 builder.with_message("expecting grant 'on' i.e.: 'grant perm +cSd+RwX on localhost:app:** to localhost:app:users:**<User>'")
5047 },
5048 "access_grant:to" => {
5049 builder.with_message("expecting grant 'to' i.e.: 'grant perm +cSd+RwX on localhost:app:** to localhost:app:users:**<User>'")
5050 },
5051 "point-subst-brute-force" => {
5052 builder.with_message("not expecting variables or working point context '.'/'..' in this point")
5053 },
5054 "access_grant_kind" => {
5055 builder.with_message("expecting access grant kind ['super','perm','priv']")
5056 },
5057
5058 what => {
5059 builder.with_message(format!("internal parser error: cannot determine an error message for parse context: {}",what))
5060 }
5061 };
5062
5063 ParseErrs::from_report(builder.finish(), loc.extra()).into()
5065 }
5066 pub fn find_parse_err<I: Span>(err: &Err<ErrorTree<I>>) -> SpaceErr {
5067 match err {
5068 Err::Incomplete(_) => "internal parser error: Incomplete".into(),
5069 Err::Error(err) => find_tree(err),
5070 Err::Failure(err) => find_tree(err),
5071 }
5072 }
5073
5074 pub enum ErrFind {
5075 Context(String),
5076 Message(String),
5077 }
5078
5079 pub fn find_tree<I: Span>(err: &ErrorTree<I>) -> SpaceErr {
5080 match err {
5081 ErrorTree::Stack { base, contexts } => {
5082 let (span, context) = contexts.first().unwrap();
5083 match context {
5084 StackContext::Context(context) => {
5085 create_err_report(*context, span.clone())
5086 }
5087 _ => "internal parser error: could not find a parse context in order to generate a useful error message".into()
5088 }
5089 }
5090 ErrorTree::Base { location, kind } => create_err_report("eof", location.clone()),
5091 ErrorTree::Alt(alts) => {
5092 for alt in alts {
5093 return find_tree(alt);
5094 }
5095
5096 "internal parser error: ErrorTree::Alt could not find a suitable context error in the various alts".into()
5097 }
5098 }
5099 }
5100
5101 pub fn first_context<I: Span>(
5102 orig: Err<ErrorTree<I>>,
5103 ) -> Result<(String, Err<ErrorTree<I>>), ()> {
5104 match &orig {
5105 Err::Error(err) => match err {
5106 ErrorTree::Stack { base, contexts } => {
5107 let (_, context) = contexts.first().unwrap();
5108 match context {
5109 StackContext::Context(context) => Ok((context.to_string(), orig)),
5110 _ => Err(()),
5111 }
5112 }
5113 _ => Err(()),
5114 },
5115 _ => Err(()),
5116 }
5117 }
5118}
5119
5120fn inclusive_any_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5121 alt((tag("+*"), tag("ROOT+*")))(input).map(|(next, _)| (next, PointSegSelector::InclusiveAny))
5122}
5123
5124fn inclusive_recursive_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5125 alt((tag("+**"), tag("ROOT+**")))(input)
5126 .map(|(next, _)| (next, PointSegSelector::InclusiveRecursive))
5127}
5128
5129fn any_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5130 tag("*")(input).map(|(next, _)| (next, PointSegSelector::Any))
5131}
5132
5133fn recursive_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5134 tag("**")(input).map(|(next, _)| (next, PointSegSelector::Recursive))
5135}
5136
5137fn exact_space_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5138 point_segment_chars(input).map(|(next, segment)| {
5139 (
5140 next,
5141 PointSegSelector::Exact(ExactPointSeg::PointSeg(PointSeg::Space(
5142 segment.to_string(),
5143 ))),
5144 )
5145 })
5146}
5147
5148fn exact_base_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5149 point_segment_chars(input).map(|(next, segment)| {
5150 (
5151 next,
5152 PointSegSelector::Exact(ExactPointSeg::PointSeg(PointSeg::Base(segment.to_string()))),
5153 )
5154 })
5155}
5156
5157fn exact_file_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5158 file_chars(input).map(|(next, segment)| {
5159 (
5160 next,
5161 PointSegSelector::Exact(ExactPointSeg::PointSeg(PointSeg::File(segment.to_string()))),
5162 )
5163 })
5164}
5165
5166fn exact_dir_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5167 file_chars(input).map(|(next, segment)| {
5168 (
5169 next,
5170 PointSegSelector::Exact(ExactPointSeg::PointSeg(PointSeg::Dir(segment.to_string()))),
5171 )
5172 })
5173}
5174
5175pub fn parse_version_chars_str<I: Span, O: FromStr>(input: I) -> Res<I, O> {
5176 let (next, rtn) = recognize(version_chars)(input)?;
5177 match O::from_str(rtn.to_string().as_str()) {
5178 Ok(rtn) => Ok((next, rtn)),
5179 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
5180 next,
5181 ErrorKind::Fail,
5182 ))),
5183 }
5184}
5185
5186fn exact_version_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5187 version_req(input).map(|(next, version_req)| (next, PointSegSelector::Version(version_req)))
5188}
5189
5190fn version_req_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5191 delimited(tag("("), version_req, tag(")"))(input)
5192 .map(|(next, version_req)| (next, PointSegSelector::Version(version_req)))
5193}
5194
5195pub fn point_segment_selector<I: Span>(input: I) -> Res<I, PointSegSelector> {
5196 alt((
5197 inclusive_recursive_segment,
5198 inclusive_any_segment,
5199 recursive_segment,
5200 any_segment,
5201 exact_space_segment,
5202 ))(input)
5203}
5204
5205fn base_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5206 alt((recursive_segment, any_segment, exact_base_segment))(input)
5207}
5208
5209fn file_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5210 alt((recursive_segment, any_segment, exact_file_segment))(input)
5211}
5212
5213fn dir_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5214 terminated(
5215 alt((recursive_segment, any_segment, exact_dir_segment)),
5216 tag("/"),
5217 )(input)
5218}
5219
5220fn dir_segment_meat<I: Span>(input: I) -> Res<I, PointSegSelector> {
5221 alt((recursive_segment, any_segment, exact_dir_segment))(input)
5222}
5223
5224fn version_segment<I: Span>(input: I) -> Res<I, PointSegSelector> {
5225 alt((
5226 recursive_segment,
5227 any_segment,
5228 exact_version_segment,
5229 version_req_segment,
5230 ))(input)
5231}
5232
5233pub fn parse_star_key<I: Span>(input: I) -> Res<I, StarKey> {
5255 let (next, (_, constelation, _, name, index)) = context(
5256 "star",
5257 tuple((
5258 tag("STAR::"),
5259 lowercase_alphanumeric,
5260 tag(":"),
5261 lowercase_alphanumeric,
5262 delimited(tag("["), digit1, tag("]")),
5263 )),
5264 )(input.clone())?;
5265 let constelation = constelation.to_string();
5266 let name = name.to_string();
5267 let index = match index.to_string().parse::<u16>() {
5268 Ok(index) => index,
5269 Err(err) => {
5270 return Err(nom::Err::Failure(ErrorTree::from_error_kind(
5271 input,
5272 ErrorKind::Digit,
5273 )))
5274 }
5275 };
5276
5277 Ok((
5278 next,
5279 StarKey {
5280 constellation: constelation,
5281 name,
5282 index,
5283 },
5284 ))
5285}
5286
5287pub fn pattern<I: Span, O, E: ParseError<I>, V>(
5288 mut value: V,
5289) -> impl FnMut(I) -> IResult<I, Pattern<O>, E>
5290where
5291 V: Parser<I, O, E>,
5292{
5293 move |input: I| {
5294 let x: Res<I, I> = tag("*")(input.clone());
5295 match x {
5296 Ok((next, _)) => Ok((next, Pattern::Any)),
5297 Err(_) => {
5298 let (next, p) = value.parse(input)?;
5299 let pattern = Pattern::Exact(p);
5300 Ok((next, pattern))
5301 }
5302 }
5303 }
5304}
5305
5306pub fn value_pattern<I: Span, O, E: ParseError<I>, F>(
5324 mut f: F,
5325) -> impl FnMut(I) -> IResult<I, ValuePattern<O>, E>
5326where
5327 I: InputLength + InputTake + Compare<&'static str>,
5328 F: Parser<I, O, E>,
5329 E: nom::error::ContextError<I>,
5330{
5331 move |input: I| match tag::<&'static str, I, E>("*")(input.clone()) {
5332 Ok((next, _)) => Ok((next, ValuePattern::Any)),
5333 Err(err) => f
5334 .parse(input.clone())
5335 .map(|(next, res)| (next, ValuePattern::Pattern(res))),
5336 }
5337}
5338pub fn version_req<I: Span>(input: I) -> Res<I, VersionReq> {
5374 let (next, version) = version_req_chars(input.clone())?;
5375 let version = version.to_string();
5376 let str_input = version.as_str();
5377 let rtn = semver::VersionReq::parse(str_input);
5378
5379 match rtn {
5380 Ok(version) => Ok((next, VersionReq { version })),
5381 Err(err) => {
5382 let tree = Err::Error(ErrorTree::from_error_kind(input, ErrorKind::Fail));
5383 Err(tree)
5384 }
5385 }
5386}
5387
5388fn rec_domain<I: Span>(input: I) -> Res<I, I> {
5389 recognize(tuple((
5390 many1(terminated(skewer_chars, tag("."))),
5391 skewer_chars,
5392 )))(input)
5393}
5394
5395fn space<I: Span>(input: I) -> Res<I, I> {
5397 recognize(alt((skewer_chars, rec_domain)))(input)
5398}
5399
5400pub fn specific_selector<I: Span>(input: I) -> Res<I, SpecificSelector> {
5401 tuple((
5402 pattern(domain),
5403 tag(":"),
5404 pattern(domain),
5405 tag(":"),
5406 pattern(skewer_case),
5407 tag(":"),
5408 pattern(skewer_case),
5409 tag(":"),
5410 delimited(tag("("), version_req, tag(")")),
5411 ))(input)
5412 .map(
5413 |(next, (provider, _, vendor, _, product, _, variant, _, version))| {
5414 let specific = SpecificSelector {
5415 provider,
5416 vendor,
5417 product,
5418 variant,
5419 version,
5420 };
5421 (next, specific)
5422 },
5423 )
5424}
5425
5426pub fn rec_domain_pattern<I: Span>(input: I) -> Res<I, Pattern<I>> {
5427 pattern(rec_domain)(input)
5428}
5429pub fn rec_skewer_pattern<I: Span>(input: I) -> Res<I, Pattern<I>> {
5430 pattern(skewer_chars)(input)
5431}
5432
5433pub fn specific_version_req<I: Span>(input: I) -> Res<I, VersionReq> {
5434 delimited(tag("("), version_req, tag(")"))(input)
5435}
5436
5437#[derive(Clone)]
5438pub struct SkewerPatternParser();
5439impl SubstParser<Pattern<String>> for SkewerPatternParser {
5440 fn parse_span<I: Span>(&self, span: I) -> Res<I, Pattern<String>> {
5441 let (next, pattern) = rec_skewer_pattern(span)?;
5442 let pattern = pattern.to_string_version();
5443 Ok((next, pattern))
5444 }
5445}
5446
5447#[derive(Clone)]
5448pub struct DomainPatternParser();
5449impl SubstParser<Pattern<String>> for DomainPatternParser {
5450 fn parse_span<I: Span>(&self, span: I) -> Res<I, Pattern<String>> {
5451 let (next, pattern) = rec_domain_pattern(span)?;
5452 let pattern = pattern.to_string_version();
5453 Ok((next, pattern))
5454 }
5455}
5456
5457pub fn kind<I: Span>(input: I) -> Res<I, Kind> {
5458 let (next, base) = kind_base(input.clone())?;
5459 unwrap_block(
5460 BlockKind::Nested(NestedBlockKind::Angle),
5461 resolve_kind(base),
5462 )(next)
5463}
5464
5465pub fn rec_kind<I: Span>(input: I) -> Res<I, I> {
5466 recognize(kind_parts)(input)
5467}
5468
5469pub fn kind_lex<I: Span>(input: I) -> Res<I, KindLex> {
5470 tuple((
5471 camel_case,
5472 opt(delimited(
5473 tag("<"),
5474 tuple((camel_case, opt(delimited(tag("<"), specific, tag(">"))))),
5475 tag(">"),
5476 )),
5477 ))(input)
5478 .map(|(next, (kind, rest))| {
5479 let mut rtn = KindLex {
5480 base: kind,
5481 sub: Option::None,
5482 specific: Option::None,
5483 };
5484
5485 match rest {
5486 Some((sub, specific)) => {
5487 rtn.sub = Option::Some(sub);
5488 match specific {
5489 Some(specific) => {
5490 rtn.specific = Option::Some(specific);
5491 }
5492 None => {}
5493 }
5494 }
5495 None => {}
5496 }
5497
5498 (next, rtn)
5499 })
5500}
5501
5502pub fn kind_parts<I: Span>(input: I) -> Res<I, KindParts> {
5503 tuple((
5504 kind_base,
5505 opt(delimited(
5506 tag("<"),
5507 tuple((camel_case, opt(delimited(tag("<"), specific, tag(">"))))),
5508 tag(">"),
5509 )),
5510 ))(input)
5511 .map(|(next, (base, rest))| {
5512 let mut rtn = KindParts {
5513 base,
5514 sub: Option::None,
5515 specific: Option::None,
5516 };
5517
5518 match rest {
5519 Some((sub, specific)) => {
5520 rtn.sub = Option::Some(sub);
5521 match specific {
5522 Some(specific) => {
5523 rtn.specific = Option::Some(specific);
5524 }
5525 None => {}
5526 }
5527 }
5528 None => {}
5529 }
5530
5531 (next, rtn)
5532 })
5533}
5534
5535pub fn delim_kind<I: Span>(input: I) -> Res<I, Kind> {
5536 delimited(tag("<"), kind, tag(">"))(input)
5537}
5538
5539pub fn delim_kind_lex<I: Span>(input: I) -> Res<I, KindLex> {
5540 delimited(tag("<"), kind_lex, tag(">"))(input)
5541}
5542
5543pub fn delim_kind_parts<I: Span>(input: I) -> Res<I, KindParts> {
5544 delimited(tag("<"), kind_parts, tag(">"))(input)
5545}
5546
5547pub fn consume_kind<I: Span>(input: I) -> Result<KindParts, SpaceErr> {
5548 let (_, kind_parts) = all_consuming(kind_parts)(input)?;
5549
5550 Ok(kind_parts.try_into()?)
5551}
5552
5553pub fn to_string<I: Span, F>(mut f: F) -> impl FnMut(I) -> Res<I, String>
5554where
5555 F: FnMut(I) -> Res<I, I> + Copy,
5556{
5557 move |input: I| {
5558 f.parse(input)
5559 .map(|(next, output)| (next, output.to_string()))
5560 }
5561}
5562
5563pub fn sub_kind_selector<I: Span>(input: I) -> Res<I, SubKindSelector> {
5564 pattern(camel_case)(input).map(|(next, selector)| match selector {
5565 Pattern::Any => (next, Pattern::Any),
5566 Pattern::Exact(sub) => (next, Pattern::Exact(Some(sub))),
5567 })
5568}
5569
5570pub fn kind_base<I: Span>(input: I) -> Res<I, BaseKind> {
5571 let (next, kind) = context("kind-base", camel_case)(input.clone())?;
5572
5573 match BaseKind::try_from(kind) {
5574 Ok(kind) => Ok((next, kind)),
5575 Err(err) => {
5576 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5577 Err(nom::Err::Error(ErrorTree::add_context(
5578 input,
5579 "kind-base",
5580 err,
5581 )))
5582 }
5583 }
5584}
5585
5586pub fn resolve_kind<I: Span>(base: BaseKind) -> impl FnMut(I) -> Res<I, Kind> {
5587 move |input: I| {
5588 let (next, sub) = context("kind-sub", camel_case)(input.clone())?;
5589 match base {
5590 BaseKind::Database => match sub.as_str() {
5591 "Relational" => {
5592 let (next, specific) =
5593 context("specific", delimited(tag("<"), specific, tag(">")))(next)?;
5594 Ok((next, Kind::Database(DatabaseSubKind::Relational(specific))))
5595 }
5596 _ => {
5597 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5598 Err(nom::Err::Error(ErrorTree::add_context(
5599 input,
5600 "kind-sub:not-found",
5601 err,
5602 )))
5603 }
5604 },
5605 BaseKind::UserBase => match sub.as_str() {
5606 "OAuth" => {
5607 let (next, specific) =
5608 context("specific", delimited(tag("<"), specific, tag(">")))(next)?;
5609 Ok((next, Kind::UserBase(UserBaseSubKind::OAuth(specific))))
5610 }
5611 _ => {
5612 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5613 Err(nom::Err::Error(ErrorTree::add_context(
5614 input,
5615 "kind-sub:not-found",
5616 err,
5617 )))
5618 }
5619 },
5620 BaseKind::Native => match NativeSub::from_str(sub.as_str()) {
5621 Ok(sub) => Ok((next, Kind::Native(sub))),
5622 Err(err) => {
5623 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5624 Err(nom::Err::Error(ErrorTree::add_context(
5625 input,
5626 "kind-sub:not-accepted",
5627 err,
5628 )))
5629 }
5630 },
5631 BaseKind::Artifact => match ArtifactSubKind::from_str(sub.as_str()) {
5632 Ok(sub) => Ok((next, Kind::Artifact(sub))),
5633 Err(err) => {
5634 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5635 Err(nom::Err::Error(ErrorTree::add_context(
5636 input,
5637 "kind-sub:not-accepted",
5638 err,
5639 )))
5640 }
5641 },
5642 BaseKind::Star => match StarSub::from_str(sub.as_str()) {
5643 Ok(sub) => Ok((next, Kind::Star(sub))),
5644 Err(err) => {
5645 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5646 Err(nom::Err::Error(ErrorTree::add_context(
5647 input,
5648 "kind-sub:not-accepted",
5649 err,
5650 )))
5651 }
5652 },
5653 BaseKind::File => match FileSubKind::from_str(sub.as_str()) {
5654 Ok(sub) => Ok((next, Kind::File(sub))),
5655 Err(err) => {
5656 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Fail);
5657 Err(nom::Err::Error(ErrorTree::add_context(
5658 input,
5659 "kind-sub:not-accepted",
5660 err,
5661 )))
5662 }
5663 },
5664 BaseKind::Root => Ok((next, Kind::Root)),
5665 BaseKind::Space => Ok((next, Kind::Space)),
5666 BaseKind::Base => Ok((next, Kind::Base)),
5667 BaseKind::User => Ok((next, Kind::User)),
5668 BaseKind::App => Ok((next, Kind::App)),
5669 BaseKind::Mechtron => Ok((next, Kind::Mechtron)),
5670 BaseKind::FileSystem => Ok((next, Kind::FileSystem)),
5671 BaseKind::BundleSeries => Ok((next, Kind::BundleSeries)),
5672 BaseKind::Bundle => Ok((next, Kind::Bundle)),
5673 BaseKind::Control => Ok((next, Kind::Control)),
5674 BaseKind::Portal => Ok((next, Kind::Portal)),
5675 BaseKind::Repo => Ok((next, Kind::Repo)),
5676 BaseKind::Driver => Ok((next, Kind::Driver)),
5677 BaseKind::Global => Ok((next, Kind::Global)),
5678 BaseKind::Host => Ok((next, Kind::Host)),
5679 BaseKind::Guest => Ok((next, Kind::Guest)),
5680 }
5681 }
5682}
5683
5684pub fn kind_base_selector<I: Span>(input: I) -> Res<I, KindBaseSelector> {
5685 pattern(kind_base)(input)
5686}
5687
5688pub fn kind_selector<I: Span>(input: I) -> Res<I, KindSelector> {
5689 delimited(
5690 tag("<"),
5691 tuple((
5692 kind_base_selector,
5693 opt(delimited(
5694 tag("<"),
5695 tuple((
5696 sub_kind_selector,
5697 opt(delimited(
5698 tag("<"),
5699 value_pattern(specific_selector),
5700 tag(">"),
5701 )),
5702 )),
5703 tag(">"),
5704 )),
5705 )),
5706 tag(">"),
5707 )(input)
5708 .map(|(next, (kind, sub_kind_and_specific))| {
5709 let (sub_kind, specific) = match sub_kind_and_specific {
5710 None => (Pattern::Any, ValuePattern::Any),
5711 Some((kind, specific)) => (
5712 kind,
5713 match specific {
5714 None => ValuePattern::Any,
5715 Some(specific) => specific,
5716 },
5717 ),
5718 };
5719
5720 let tks = KindSelector {
5721 base: kind,
5722 sub: sub_kind,
5723 specific,
5724 };
5725
5726 (next, tks)
5727 })
5728}
5729
5730fn space_hop<I: Span>(input: I) -> Res<I, Hop> {
5731 tuple((point_segment_selector, opt(kind_selector), opt(tag("+"))))(input).map(
5732 |(next, (segment_selector, kind_selector, inclusive))| {
5733 let kind_selector = match kind_selector {
5734 None => KindSelector::any(),
5735 Some(tks) => tks,
5736 };
5737 let inclusive = inclusive.is_some();
5738 (
5739 next,
5740 Hop {
5741 inclusive,
5742 segment_selector,
5743 kind_selector,
5744 },
5745 )
5746 },
5747 )
5748}
5749
5750fn base_hop<I: Span>(input: I) -> Res<I, Hop> {
5751 tuple((base_segment, opt(kind_selector), opt(tag("+"))))(input).map(
5752 |(next, (segment, tks, inclusive))| {
5753 let tks = match tks {
5754 None => KindSelector::any(),
5755 Some(tks) => tks,
5756 };
5757 let inclusive = inclusive.is_some();
5758 (
5759 next,
5760 Hop {
5761 inclusive,
5762 segment_selector: segment,
5763 kind_selector: tks,
5764 },
5765 )
5766 },
5767 )
5768}
5769
5770fn file_hop<I: Span>(input: I) -> Res<I, Hop> {
5771 tuple((file_segment, opt(tag("+"))))(input).map(|(next, (segment, inclusive))| {
5772 let tks = KindSelector {
5773 base: Pattern::Exact(BaseKind::File),
5774 sub: Pattern::Any,
5775 specific: ValuePattern::Any,
5776 };
5777 let inclusive = inclusive.is_some();
5778 (
5779 next,
5780 Hop {
5781 inclusive,
5782 segment_selector: segment,
5783 kind_selector: tks,
5784 },
5785 )
5786 })
5787}
5788
5789fn dir_hop<I: Span>(input: I) -> Res<I, Hop> {
5790 tuple((dir_segment, opt(tag("+"))))(input).map(|(next, (segment, inclusive))| {
5791 let tks = KindSelector::any();
5792 let inclusive = inclusive.is_some();
5793 (
5794 next,
5795 Hop {
5796 inclusive,
5797 segment_selector: segment,
5798 kind_selector: tks,
5799 },
5800 )
5801 })
5802}
5803
5804fn version_hop<I: Span>(input: I) -> Res<I, Hop> {
5805 tuple((version_segment, opt(kind_selector), opt(tag("+"))))(input).map(
5806 |(next, (segment, tks, inclusive))| {
5807 let tks = match tks {
5808 None => KindSelector::any(),
5809 Some(tks) => tks,
5810 };
5811 let inclusive = inclusive.is_some();
5812 (
5813 next,
5814 Hop {
5815 inclusive,
5816 segment_selector: segment,
5817 kind_selector: tks,
5818 },
5819 )
5820 },
5821 )
5822}
5823
5824pub fn point_selector<I: Span>(input: I) -> Res<I, Selector> {
5825 context(
5826 "point_kind_pattern",
5827 tuple((
5828 space_hop,
5829 many0(preceded(tag(":"), base_hop)),
5830 opt(preceded(tag(":"), version_hop)),
5831 opt(preceded(tag(":/"), tuple((many0(dir_hop), opt(file_hop))))),
5832 )),
5833 )(input)
5834 .map(
5835 |(next, (space_hop, base_hops, version_hop, filesystem_hops))| {
5836 let mut hops = vec![];
5837 hops.push(space_hop);
5838 for base_hop in base_hops {
5839 hops.push(base_hop);
5840 }
5841 if let Option::Some(version_hop) = version_hop {
5842 hops.push(version_hop);
5843 }
5844 if let Some((dir_hops, file_hop)) = filesystem_hops {
5845 hops.push(Hop {
5847 inclusive: false,
5848 segment_selector: PointSegSelector::Exact(ExactPointSeg::PointSeg(
5849 PointSeg::FilesystemRootDir,
5850 )),
5851 kind_selector: KindSelector {
5852 base: Pattern::Exact(BaseKind::File),
5853 sub: Pattern::Any,
5854 specific: ValuePattern::Any,
5855 },
5856 });
5857 for dir_hop in dir_hops {
5858 hops.push(dir_hop);
5859 }
5860 if let Some(file_hop) = file_hop {
5861 hops.push(file_hop);
5862 }
5863 }
5864
5865 let rtn = Selector { hops };
5866
5867 (next, rtn)
5868 },
5869 )
5870}
5871
5872pub fn point_and_kind<I: Span>(input: I) -> Res<I, PointKindVar> {
5873 tuple((point_var, kind))(input)
5874 .map(|(next, (point, kind))| (next, PointKindVar { point, kind }))
5875}
5876
5877pub fn version<I: Span>(input: I) -> Res<I, Version> {
5896 let (next, version) = rec_version(input.clone())?;
5897 let version = version.to_string();
5898 let str_input = version.as_str();
5899 let rtn = semver::Version::parse(str_input);
5900
5901 match rtn {
5902 Ok(version) => Ok((next, Version { version })),
5903 Err(err) => {
5904 let tree = Err::Error(ErrorTree::from_error_kind(input, ErrorKind::Fail));
5905 Err(tree)
5906 }
5907 }
5908}
5909
5910pub fn specific<I: Span>(input: I) -> Res<I, Specific> {
5911 tuple((
5912 domain,
5913 tag(":"),
5914 domain,
5915 tag(":"),
5916 skewer_case,
5917 tag(":"),
5918 skewer_case,
5919 tag(":"),
5920 version,
5921 ))(input)
5922 .map(
5923 |(next, (provider, _, vendor, _, product, _, variant, _, version))| {
5924 let specific = Specific {
5925 provider,
5926 vendor,
5927 product,
5928 variant,
5929 version,
5930 };
5931 (next, specific)
5932 },
5933 )
5934}
5935pub fn args<T>(i: T) -> Res<T, T>
5938where
5939 T: InputTakeAtPosition + nom::InputLength,
5940 <T as InputTakeAtPosition>::Item: AsChar,
5941{
5942 i.split_at_position1_complete(
5943 |item| {
5944 let char_item = item.as_char();
5945 !(char_item == '-')
5946 && !(char_item == '"')
5947 && !(char_item == '_')
5948 && !(char_item == '{')
5949 && !(char_item == '}')
5950 && !(char_item == '(')
5951 && !(char_item == ')')
5952 && !(char_item == '[')
5953 && !(char_item == ']')
5954 && !(char_item == ' ')
5955 && !(char_item == '\n')
5956 && !(char_item == '\t')
5957 && !(char_item == '\r')
5958 && !(char_item == '\'')
5959 && !((char_item.is_alphanumeric()) || char_item.is_dec_digit())
5960 },
5961 ErrorKind::AlphaNumeric,
5962 )
5963}
5964
5965pub fn skewer<T>(i: T) -> Res<T, T>
5966where
5967 T: InputTakeAtPosition + nom::InputLength,
5968 <T as InputTakeAtPosition>::Item: AsChar,
5969{
5970 i.split_at_position1_complete(
5971 |item| {
5972 let char_item = item.as_char();
5973 !(char_item == '-')
5974 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
5975 },
5976 ErrorKind::AlphaNumeric,
5977 )
5978}
5979
5980pub fn skewer_or_snake<T>(i: T) -> Res<T, T>
5981where
5982 T: InputTakeAtPosition + nom::InputLength,
5983 <T as InputTakeAtPosition>::Item: AsChar,
5984{
5985 i.split_at_position1_complete(
5986 |item| {
5987 let char_item = item.as_char();
5988 !(char_item == '-')
5989 && !(char_item == '_')
5990 && !((char_item.is_alpha() && char_item.is_lowercase()) || char_item.is_dec_digit())
5991 },
5992 ErrorKind::AlphaNumeric,
5993 )
5994}
5995
5996pub fn not_quote<T>(i: T) -> Res<T, T>
5997where
5998 T: InputTakeAtPosition + nom::InputLength,
5999 <T as InputTakeAtPosition>::Item: AsChar,
6000{
6001 i.split_at_position1_complete(
6002 |item| {
6003 let char_item = item.as_char();
6004 (char_item == '"')
6005 },
6006 ErrorKind::AlphaNumeric,
6007 )
6008}
6009
6010pub fn filename<T>(i: T) -> Res<T, T>
6011where
6012 T: InputTakeAtPosition + nom::InputLength,
6013 <T as InputTakeAtPosition>::Item: AsChar,
6014{
6015 i.split_at_position1_complete(
6016 |item| {
6017 let char_item = item.as_char();
6018 !(char_item == '-') && !(char_item.is_alpha() || char_item.is_dec_digit())
6019 },
6020 ErrorKind::AlphaNumeric,
6021 )
6022}
6023
6024pub fn primitive_def<I: Span>(input: I) -> Res<I, PayloadType2Def<PointVar>> {
6025 tuple((
6026 payload,
6027 opt(preceded(tag("~"), opt(format))),
6028 opt(preceded(tag("~"), call_with_config)),
6029 ))(input)
6030 .map(|(next, (primitive, format, verifier))| {
6031 (
6032 next,
6033 PayloadType2Def {
6034 primitive,
6035 format: match format {
6036 Some(Some(format)) => Some(format),
6037 _ => Option::None,
6038 },
6039 verifier,
6040 },
6041 )
6042 })
6043}
6044
6045pub fn payload<I: Span>(input: I) -> Res<I, SubstanceKind> {
6046 parse_camel_case_str(input)
6047}
6048
6049pub fn consume_primitive_def<I: Span>(input: I) -> Res<I, PayloadType2Def<PointVar>> {
6050 all_consuming(primitive_def)(input)
6051}
6052
6053pub fn call_with_config<I: Span>(input: I) -> Res<I, CallWithConfigVar> {
6054 tuple((call, opt(preceded(tag("+"), point_var))))(input)
6055 .map(|(next, (call, config))| (next, CallWithConfigVar { call, config }))
6056}
6057
6058pub fn parse_alpha1_str<I: Span, O: FromStr>(input: I) -> Res<I, O> {
6059 let (next, rtn) = recognize(alpha1)(input)?;
6060 match O::from_str(rtn.to_string().as_str()) {
6061 Ok(rtn) => Ok((next, rtn)),
6062 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6063 next,
6064 ErrorKind::Fail,
6065 ))),
6066 }
6067}
6068
6069pub fn rc_command<I: Span>(input: I) -> Res<I, CmdKind> {
6070 parse_alpha1_str(input)
6071}
6072
6073pub fn ext_call<I: Span>(input: I) -> Res<I, CallKind> {
6074 tuple((
6075 delimited(tag("Ext<"), ext_method, tag(">")),
6076 opt(subst_path),
6077 ))(input)
6078 .map(|(next, (method, path))| {
6079 let path = match path {
6080 None => subst(filepath_chars)(new_span("/")).unwrap().1.stringify(),
6081 Some(path) => path.stringify(),
6082 };
6083 (next, CallKind::Ext(ExtCall::new(method, path)))
6084 })
6085}
6086
6087pub fn http_call<I: Span>(input: I) -> Res<I, CallKind> {
6088 tuple((
6089 delimited(tag("Http<"), http_method, tag(">")),
6090 opt(subst_path),
6091 ))(input)
6092 .map(|(next, (method, path))| {
6093 let path = match path {
6094 None => subst(filepath_chars)(new_span("/")).unwrap().1.stringify(),
6095 Some(path) => path.stringify(),
6096 };
6097 (next, CallKind::Http(HttpCall::new(method, path)))
6098 })
6099}
6100
6101pub fn call_kind<I: Span>(input: I) -> Res<I, CallKind> {
6102 alt((ext_call, http_call))(input)
6103}
6104
6105pub fn call<I: Span>(input: I) -> Res<I, CallVar> {
6106 tuple((point_var, preceded(tag("^"), call_kind)))(input)
6107 .map(|(next, (point, kind))| (next, CallVar { point, kind }))
6108}
6109
6110pub fn consume_call<I: Span>(input: I) -> Res<I, CallVar> {
6111 all_consuming(call)(input)
6112}
6113
6114pub fn labeled_primitive_def<I: Span>(input: I) -> Res<I, LabeledPrimitiveTypeDef<PointVar>> {
6115 tuple((skewer, delimited(tag("<"), primitive_def, tag(">"))))(input).map(
6116 |(next, (label, primitive_def))| {
6117 let labeled_def = LabeledPrimitiveTypeDef {
6118 label: label.to_string(),
6119 def: primitive_def,
6120 };
6121 (next, labeled_def)
6122 },
6123 )
6124}
6125
6126pub fn digit_range<I: Span>(input: I) -> Res<I, NumRange> {
6127 tuple((digit1, tag("-"), digit1))(input).map(|(next, (min, _, max))| {
6128 let min: usize = usize::from_str(min.to_string().as_str()).expect("usize");
6129 let max: usize = usize::from_str(max.to_string().as_str()).expect("usize");
6130 let range = NumRange::MinMax { min, max };
6131
6132 (next, range)
6133 })
6134}
6135
6136pub fn exact_range<I: Span>(input: I) -> Res<I, NumRange> {
6137 digit1(input).map(|(next, exact)| {
6138 (
6139 next,
6140 NumRange::Exact(
6141 usize::from_str(exact.to_string().as_str())
6142 .expect("expect to be able to change digit string into usize"),
6143 ),
6144 )
6145 })
6146}
6147
6148pub fn range<I: Span>(input: I) -> Res<I, NumRange> {
6149 delimited(
6150 multispace0,
6151 opt(alt((digit_range, exact_range))),
6152 multispace0,
6153 )(input)
6154 .map(|(next, range)| {
6155 let range = match range {
6156 Some(range) => range,
6157 None => NumRange::Any,
6158 };
6159 (next, range)
6160 })
6161}
6162
6163pub fn primitive_data_struct<I: Span>(input: I) -> Res<I, SubstanceTypePatternDef<PointVar>> {
6164 context("selector", payload)(input)
6165 .map(|(next, primitive)| (next, SubstanceTypePatternDef::Primitive(primitive)))
6166}
6167
6168pub fn array_data_struct<I: Span>(input: I) -> Res<I, SubstanceTypePatternDef<PointVar>> {
6169 context(
6170 "selector",
6171 tuple((
6172 payload,
6173 context("array", delimited(tag("["), range, tag("]"))),
6174 )),
6175 )(input)
6176 .map(|(next, (primitive, range))| {
6177 (
6178 next,
6179 SubstanceTypePatternDef::List(ListPattern { primitive, range }),
6180 )
6181 })
6182}
6183
6184pub fn map_entry_pattern_any<I: Span>(input: I) -> Res<I, ValuePattern<MapEntryPatternVar>> {
6185 delimited(multispace0, tag("*"), multispace0)(input).map(|(next, _)| (next, ValuePattern::Any))
6186}
6187
6188pub fn map_entry_pattern<I: Span>(input: I) -> Res<I, MapEntryPatternVar> {
6189 tuple((skewer, opt(delimited(tag("<"), payload_pattern, tag(">")))))(input).map(
6190 |(next, (key_con, payload_con))| {
6191 let payload_con = match payload_con {
6192 None => ValuePattern::Any,
6193 Some(payload_con) => payload_con,
6194 };
6195
6196 let map_entry_con = MapEntryPatternVar {
6197 key: key_con.to_string(),
6198 payload: payload_con,
6199 };
6200 (next, map_entry_con)
6201 },
6202 )
6203}
6204
6205pub fn map_entry_patterns<I: Span>(input: I) -> Res<I, Vec<MapEntryPatternVar>> {
6206 separated_list0(
6207 delimited(multispace0, tag(","), multispace0),
6208 map_entry_pattern,
6209 )(input)
6210}
6211
6212pub fn consume_map_entry_pattern<I: Span>(input: I) -> Res<I, MapEntryPatternVar> {
6213 all_consuming(map_entry_pattern)(input)
6214}
6215
6216pub fn required_map_entry_pattern<I: Span>(input: I) -> Res<I, Vec<MapEntryPatternVar>> {
6217 delimited(tag("["), map_entry_patterns, tag("]"))(input).map(|(next, params)| (next, params))
6218}
6219
6220pub fn allowed_map_entry_pattern<I: Span>(input: I) -> Res<I, ValuePattern<SubstancePatternVar>> {
6221 payload_pattern(input).map(|(next, con)| (next, con))
6222}
6223
6224pub fn map_pattern_params<I: Span>(input: I) -> Res<I, MapPatternVar> {
6226 tuple((
6227 opt(map_entry_patterns),
6228 multispace0,
6229 opt(allowed_map_entry_pattern),
6230 ))(input)
6231 .map(|(next, (required, _, allowed))| {
6232 let mut required_map = HashMap::new();
6233 match required {
6234 Option::Some(required) => {
6235 for require in required {
6236 required_map.insert(require.key, require.payload);
6237 }
6238 }
6239 Option::None => {}
6240 }
6241
6242 let allowed = match allowed {
6243 Some(allowed) => allowed,
6244 None => ValuePattern::None,
6245 };
6246
6247 let con = MapPatternVar::new(required_map, allowed);
6248
6249 (next, con)
6250 })
6251}
6252
6253pub fn format<I: Span>(input: I) -> Res<I, SubstanceFormat> {
6254 let (next, format) = recognize(alpha1)(input)?;
6255 match SubstanceFormat::from_str(format.to_string().as_str()) {
6256 Ok(format) => Ok((next, format)),
6257 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6258 next,
6259 ErrorKind::Fail,
6260 ))),
6261 }
6262}
6263
6264enum MapConParam {
6265 Required(Vec<ValuePattern<MapEntryPattern>>),
6266 Allowed(ValuePattern<SubstancePattern>),
6267}
6268
6269pub fn map_pattern<I: Span>(input: I) -> Res<I, MapPatternVar> {
6272 tuple((
6273 delimited(multispace0, tag("Map"), multispace0),
6274 opt(delimited(
6275 tag("{"),
6276 delimited(multispace0, map_pattern_params, multispace0),
6277 tag("}"),
6278 )),
6279 ))(input)
6280 .map(|(next, (_, entries))| {
6281 let mut entries = entries;
6282 let con = match entries {
6283 None => MapPatternVar::any(),
6284 Some(con) => con,
6285 };
6286
6287 (next, con)
6288 })
6289}
6290
6291pub fn value_constrained_map_pattern<I: Span>(input: I) -> Res<I, ValuePattern<MapPatternVar>> {
6292 value_pattern(map_pattern)(input)
6293}
6294
6295pub fn ext_action<I: Span>(input: I) -> Res<I, ValuePattern<StringMatcher>> {
6296 value_pattern(camel_case_to_string_matcher)(input)
6297}
6298
6299pub fn parse_camel_case_str<I: Span, O: FromStr>(input: I) -> Res<I, O> {
6300 let (next, rtn) = recognize(camel_case_chars)(input)?;
6301 match O::from_str(rtn.to_string().as_str()) {
6302 Ok(rtn) => Ok((next, rtn)),
6303 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6304 next,
6305 ErrorKind::Fail,
6306 ))),
6307 }
6308}
6309
6310pub fn http_method<I: Span>(input: I) -> Res<I, HttpMethod> {
6311 context("http_method", parse_camel_case_str).parse(input)
6312}
6313
6314pub fn http_method_pattern<I: Span>(input: I) -> Res<I, HttpMethodPattern> {
6315 context("@http_method_pattern", method_pattern(http_method))(input)
6316}
6317
6318pub fn method_pattern<I: Clone, E: ParseError<I>, F>(
6319 mut f: F,
6320) -> impl FnMut(I) -> IResult<I, HttpMethodPattern, E>
6321where
6322 I: InputLength + InputTake + Compare<&'static str>,
6323 F: Parser<I, HttpMethod, E>,
6324 E: nom::error::ContextError<I>,
6325{
6326 move |input: I| match tag::<&'static str, I, E>("*")(input.clone()) {
6327 Ok((next, _)) => Ok((next, HttpMethodPattern::Any)),
6328 Err(err) => f
6329 .parse(input.clone())
6330 .map(|(next, res)| (next, HttpMethodPattern::Pattern(res))),
6331 }
6332}
6333
6334pub fn ext_method<I: Span>(input: I) -> Res<I, ExtMethod> {
6335 let (next, ext_method) = camel_case_chars(input.clone())?;
6336
6337 match ExtMethod::new(ext_method.to_string()) {
6338 Ok(method) => Ok((next, method)),
6339 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6340 input,
6341 ErrorKind::Fail,
6342 ))),
6343 }
6344}
6345
6346pub fn sys_method<I: Span>(input: I) -> Res<I, HypMethod> {
6347 let (next, sys_method) = camel_case_chars(input.clone())?;
6348
6349 match HypMethod::from_str(sys_method.to_string().as_str()) {
6350 Ok(method) => Ok((next, method)),
6351 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6352 input,
6353 ErrorKind::Fail,
6354 ))),
6355 }
6356}
6357
6358pub fn cmd_method<I: Span>(input: I) -> Res<I, CmdMethod> {
6359 let (next, method) = camel_case_chars(input.clone())?;
6360
6361 match CmdMethod::from_str(method.to_string().as_str()) {
6362 Ok(method) => Ok((next, method)),
6363 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6364 input,
6365 ErrorKind::Fail,
6366 ))),
6367 }
6368}
6369
6370pub fn wrapped_ext_method<I: Span>(input: I) -> Res<I, Method> {
6371 let (next, ext_method) = ext_method(input.clone())?;
6372
6373 match ExtMethod::new(ext_method.to_string()) {
6374 Ok(method) => Ok((next, Method::Ext(method))),
6375 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
6376 input,
6377 ErrorKind::Fail,
6378 ))),
6379 }
6380}
6381
6382pub fn wrapped_http_method<I: Span>(input: I) -> Res<I, Method> {
6383 http_method(input).map(|(next, method)| (next, Method::Http(method)))
6384}
6385
6386pub fn wrapped_sys_method<I: Span>(input: I) -> Res<I, Method> {
6387 sys_method(input).map(|(next, method)| (next, Method::Hyp(method)))
6388}
6389
6390pub fn wrapped_cmd_method<I: Span>(input: I) -> Res<I, Method> {
6391 cmd_method(input).map(|(next, method)| (next, Method::Cmd(method)))
6392}
6393
6394pub fn rc_command_type<I: Span>(input: I) -> Res<I, CmdKind> {
6395 parse_alpha1_str(input)
6396}
6397
6398pub fn map_pattern_payload_structure<I: Span>(
6399 input: I,
6400) -> Res<I, SubstanceTypePatternDef<PointVar>> {
6401 map_pattern(input).map(|(next, con)| (next, SubstanceTypePatternDef::Map(Box::new(con))))
6402}
6403
6404pub fn payload_structure<I: Span>(input: I) -> Res<I, SubstanceTypePatternDef<PointVar>> {
6405 alt((
6406 array_data_struct,
6407 primitive_data_struct,
6408 map_pattern_payload_structure,
6409 ))(input)
6410}
6411
6412pub fn payload_structure_with_validation<I: Span>(input: I) -> Res<I, SubstancePatternVar> {
6413 tuple((
6414 context("selector", payload_structure),
6415 opt(preceded(tag("~"), opt(format))),
6416 opt(preceded(tag("~"), call_with_config)),
6417 ))(input)
6418 .map(|(next, (data, format, verifier))| {
6419 (
6420 next,
6421 SubstancePatternVar {
6422 structure: data,
6423 format: match format {
6424 Some(Some(format)) => Some(format),
6425 _ => Option::None,
6426 },
6427 validator: verifier,
6428 },
6429 )
6430 })
6431}
6432
6433pub fn consume_payload_structure<I: Span>(input: I) -> Res<I, SubstanceTypePatternVar> {
6434 all_consuming(payload_structure)(input)
6435}
6436
6437pub fn consume_data_struct_def<I: Span>(input: I) -> Res<I, SubstancePatternVar> {
6438 all_consuming(payload_structure_with_validation)(input)
6439}
6440
6441pub fn payload_pattern_any<I: Span>(input: I) -> Res<I, ValuePattern<SubstancePatternVar>> {
6442 tag("*")(input).map(|(next, _)| (next, ValuePattern::Any))
6443}
6444
6445pub fn payload_pattern<I: Span>(input: I) -> Res<I, ValuePattern<SubstancePatternVar>> {
6446 context(
6447 "@payload-pattern",
6448 value_pattern(payload_structure_with_validation),
6449 )(input)
6450 .map(|(next, payload_pattern)| (next, payload_pattern))
6451}
6452
6453pub fn payload_filter_block_empty<I: Span>(input: I) -> Res<I, PatternBlockVar> {
6454 multispace0(input.clone()).map(|(next, _)| (input, PatternBlockVar::None))
6455}
6456
6457pub fn payload_filter_block_any<I: Span>(input: I) -> Res<I, PatternBlockVar> {
6458 let (next, _) = delimited(multispace0, context("selector", tag("*")), multispace0)(input)?;
6459
6460 Ok((next, PatternBlockVar::Any))
6461}
6462
6463pub fn payload_filter_block_def<I: Span>(input: I) -> Res<I, PatternBlockVar> {
6464 payload_structure_with_validation(input)
6465 .map(|(next, pattern)| (next, PatternBlockVar::Pattern(pattern)))
6466}
6467
6468fn insert_block_pattern<I: Span>(input: I) -> Res<I, UploadBlock> {
6469 delimited(multispace0, filename, multispace0)(input).map(|(next, filename)| {
6470 (
6471 next,
6472 UploadBlock {
6473 name: filename.to_string(),
6474 },
6475 )
6476 })
6477}
6478
6479pub fn upload_payload_block<I: Span>(input: I) -> Res<I, UploadBlock> {
6499 delimited(multispace0, file_chars, multispace0)(input).map(|(next, filename)| {
6500 (
6501 next,
6502 UploadBlock {
6503 name: filename.to_string(),
6504 },
6505 )
6506 })
6507}
6508
6509pub fn upload_block<I: Span>(input: I) -> Res<I, UploadBlock> {
6510 delimited(tag("^["), upload_payload_block, tag("]->"))(input)
6511}
6512
6513pub fn upload_blocks<I: Span>(input: I) -> Res<I, Vec<UploadBlock>> {
6514 many0(pair(take_until("^["), upload_block))(input).map(|(next, blocks)| {
6515 let mut rtn = vec![];
6516 for (_, block) in blocks {
6517 rtn.push(block);
6518 }
6519 (next, rtn)
6520 })
6521}
6522
6523pub fn request_payload_filter_block<I: Span>(input: I) -> Res<I, PayloadBlockVar> {
6524 tuple((
6525 multispace0,
6526 alt((
6527 payload_filter_block_any,
6528 payload_filter_block_def,
6529 payload_filter_block_empty,
6530 )),
6531 multispace0,
6532 ))(input)
6533 .map(|(next, (_, block, _))| (next, PayloadBlockVar::DirectPattern(block)))
6534}
6535
6536pub fn response_payload_filter_block<I: Span>(input: I) -> Res<I, PayloadBlockVar> {
6537 context(
6538 "response-payload-filter-block",
6539 terminated(
6540 tuple((
6541 multispace0,
6542 alt((
6543 payload_filter_block_any,
6544 payload_filter_block_def,
6545 payload_filter_block_empty,
6546 fail,
6547 )),
6548 multispace0,
6549 )),
6550 tag("]"),
6551 ),
6552 )(input)
6553 .map(|(next, (_, block, _))| (next, PayloadBlockVar::ReflectPattern(block)))
6554}
6555
6556pub fn rough_pipeline_step<I: Span>(input: I) -> Res<I, I> {
6557 recognize(tuple((
6558 many0(preceded(
6559 alt((tag("-"), tag("="), tag("+"))),
6560 any_soround_lex_block,
6561 )),
6562 alt((tag("->"), tag("=>"))),
6563 )))(input)
6564}
6565
6566pub fn consume_pipeline_block<I: Span>(input: I) -> Res<I, PayloadBlockVar> {
6567 all_consuming(request_payload_filter_block)(input)
6568}
6569
6570pub fn strip_comments<I: Span>(input: I) -> Res<I, String>
6579where
6580 I: InputTakeAtPosition + nom::InputLength + Clone + ToString,
6581 <I as InputTakeAtPosition>::Item: AsChar,
6582{
6583 many0(alt((no_comment, comment)))(input).map(|(next, texts)| {
6584 let mut rtn = String::new();
6585 for t in texts {
6586 match t {
6587 TextType::NoComment(span) => {
6588 rtn.push_str(span.to_string().as_str());
6589 }
6590 TextType::Comment(span) => {
6591 for i in 0..span.input_len() {
6592 rtn.push_str(" ");
6594 }
6595 }
6596 }
6597 }
6598
6599 (next, rtn)
6602 })
6603}
6604
6605pub fn no_comment<T: Span>(i: T) -> Res<T, TextType<T>>
6616where
6617 T: InputTakeAtPosition + nom::InputLength,
6618 <T as InputTakeAtPosition>::Item: AsChar,
6619{
6620 i.split_at_position1_complete(
6621 |item| {
6622 let char_item = item.as_char();
6623 char_item == '#'
6624 },
6625 ErrorKind::AlphaNumeric,
6626 )
6627 .map(|(next, comment)| (next, TextType::NoComment(comment)))
6628}
6629
6630pub fn comment<T: Span>(i: T) -> Res<T, TextType<T>>
6631where
6632 T: InputTakeAtPosition + nom::InputLength,
6633 <T as InputTakeAtPosition>::Item: AsChar,
6634{
6635 i.split_at_position1_complete(
6636 |item| {
6637 let char_item = item.as_char();
6638 char_item == '\n'
6639 },
6640 ErrorKind::AlphaNumeric,
6641 )
6642 .map(|(next, comment)| (next, TextType::Comment(comment)))
6643}
6644
6645pub fn bind_config(src: &str) -> Result<BindConfig, SpaceErr> {
6646 let document = doc(src)?;
6647 match document {
6648 Document::BindConfig(bind_config) => Ok(bind_config),
6649 _ => Err("not a bind config".into()),
6650 }
6651}
6652
6653pub fn mechtron_config(src: &str) -> Result<MechtronConfig, SpaceErr> {
6654 let document = doc(src)?;
6655 match document {
6656 Document::MechtronConfig(mechtron_config) => Ok(mechtron_config),
6657 _ => Err("not a Mechtron config".into()),
6658 }
6659}
6660
6661pub fn doc(src: &str) -> Result<Document, SpaceErr> {
6662 let src = src.to_string();
6663 let (next, stripped) = strip_comments(new_span(src.as_str()))?;
6664 let span = span_with_extra(stripped.as_str(), Arc::new(src.to_string()));
6665 let lex_root_scope = lex_root_scope(span.clone())?;
6666 let root_scope_selector = lex_root_scope.selector.clone().to_concrete()?;
6667 if root_scope_selector.name.as_str() == "Mechtron" {
6668 if root_scope_selector.version == Version::from_str("1.0.0")? {
6669 let mechtron = result(parse_mechtron_config(lex_root_scope.block.content.clone()))?;
6670
6671 let mechtron = MechtronConfig::new(mechtron)?;
6672 return Ok(Document::MechtronConfig(mechtron));
6673 } else {
6674 let message = format!(
6675 "ConfigParser does not know how to process a Bind at version '{}'",
6676 root_scope_selector.version.to_string()
6677 );
6678 let mut builder = Report::build(ReportKind::Error, (), 0);
6679 let report = builder
6680 .with_message(message)
6681 .with_label(
6682 Label::new(
6683 lex_root_scope.selector.version.span.location_offset()
6684 ..lex_root_scope.selector.version.span.location_offset()
6685 + lex_root_scope.selector.version.span.len(),
6686 )
6687 .with_message("Unsupported Bind Config Version"),
6688 )
6689 .finish();
6690 Err(ParseErrs::from_report(report, lex_root_scope.block.content.extra.clone()).into())
6691 }
6692 } else if root_scope_selector.name.as_str() == "Bind" {
6693 if root_scope_selector.version == Version::from_str("1.0.0")? {
6694 let bind = parse_bind_config(lex_root_scope.block.content.clone())?;
6695
6696 return Ok(Document::BindConfig(bind));
6697 } else {
6698 let message = format!(
6699 "ConfigParser does not know how to process a Bind at version '{}'",
6700 root_scope_selector.version.to_string()
6701 );
6702 let mut builder = Report::build(ReportKind::Error, (), 0);
6703 let report = builder
6704 .with_message(message)
6705 .with_label(
6706 Label::new(
6707 lex_root_scope.selector.version.span.location_offset()
6708 ..lex_root_scope.selector.version.span.location_offset()
6709 + lex_root_scope.selector.version.span.len(),
6710 )
6711 .with_message("Unsupported Bind Config Version"),
6712 )
6713 .finish();
6714 Err(ParseErrs::from_report(report, lex_root_scope.block.content.extra.clone()).into())
6715 }
6716 } else {
6717 let message = format!(
6718 "ConfigParser does not know how to process a '{}'",
6719 lex_root_scope.selector.name.to_string(),
6720 );
6721 let mut builder = Report::build(ReportKind::Error, (), 0);
6722 let report = builder
6723 .with_message(message)
6724 .with_label(
6725 Label::new(
6726 lex_root_scope.selector.name.location_offset()
6727 ..lex_root_scope.selector.name.location_offset()
6728 + lex_root_scope.selector.name.len(),
6729 )
6730 .with_message("Unrecognized Config Kind"),
6731 )
6732 .finish();
6733 Err(ParseErrs::from_report(report, lex_root_scope.block.content.extra.clone()).into())
6734 }
6735}
6736
6737fn parse_mechtron_config<I: Span>(input: I) -> Res<I,Vec<MechtronScope>> {
6738 let (next, (_,( _, (_,assignments)))) = pair( multispace0, context("wasm",tuple((
6739 tag("Wasm"),
6740 alt((tuple((
6741 multispace0,
6742 unwrap_block(BlockKind::Nested(NestedBlockKind::Curly),many0(assignment)))
6743 ),fail))),
6744 )))(input)?;
6745 Ok((next,vec![MechtronScope::WasmScope(assignments)]))
6746}
6747
6748fn assignment<I>(input: I) -> Res<I, Assignment>
6749where
6750 I: Span,
6751{
6752 tuple((
6753 multispace0,
6754 context("assignment:plus", alt( (tag("+"),fail))),
6755 context("assignment:key", alt( (skewer,fail))),
6756 multispace0,
6757 context( "assignment:equals", alt((tag("="),fail))),
6758 multispace0,
6759 context( "assignment:value", alt((nospace1_nosemi,fail))),
6760 multispace0,
6761 opt(tag(";")),
6762 multispace0
6763 ))(input)
6764 .map(|(next, (_, _, k, _, _, _, v, _, _, _))| {
6765 (
6766 next,
6767 Assignment {
6768 key: k.to_string(),
6769 value: v.to_string(),
6770 },
6771 )
6772 })
6773}
6774
6775#[derive(Clone)]
6776pub struct Assignment {
6777 pub key: String,
6778 pub value: String,
6779}
6780
6781fn semantic_mechtron_scope<I: Span>(scope: LexScope<I>) -> Result<MechtronScope, SpaceErr> {
6782 let selector_name = scope.selector.name.to_string();
6783 match selector_name.as_str() {
6784 "Wasm" => {
6785 let assignments = result(many0(assignment)(scope.block.content))?;
6786 Ok(MechtronScope::WasmScope(assignments))
6787 }
6788 what => {
6789 let mut builder = Report::build(ReportKind::Error, (), 0);
6790 let report = builder
6791 .with_message(format!(
6792 "Unrecognized MechtronConfig selector: '{}'",
6793 scope.selector.name.to_string()
6794 ))
6795 .with_label(
6796 Label::new(
6797 scope.selector.name.location_offset()
6798 ..scope.selector.name.location_offset() + scope.selector.name.len(),
6799 )
6800 .with_message("Unrecognized Selector"),
6801 )
6802 .finish();
6803 Err(ParseErrs::from_report(report, scope.block.content.extra().clone()).into())
6804 }
6805 }
6806}
6807
6808fn parse_bind_config<I: Span>(input: I) -> Result<BindConfig, SpaceErr> {
6809 let lex_scopes = lex_scopes(input)?;
6810 let mut scopes = vec![];
6811 let mut errors = vec![];
6812
6813 for lex_scope in lex_scopes {
6814 match semantic_bind_scope(lex_scope) {
6815 Ok(scope) => {
6816 scopes.push(scope);
6817 }
6818 Err(err) => errors.push(err),
6819 }
6820 }
6821
6822 if !errors.is_empty() {
6823 let errors = ParseErrs::fold(errors);
6824 return Err(errors.into());
6825 }
6826
6827 let mut config = BindConfig::new(scopes);
6828 Ok(config)
6829}
6830
6831fn semantic_bind_scope<I: Span>(scope: LexScope<I>) -> Result<BindScope, SpaceErr> {
6832 let selector_name = scope.selector.name.to_string();
6833 match selector_name.as_str() {
6834 "Route" => {
6835 let scope = lex_child_scopes(scope)?;
6836 let scope = RouteScope::try_from(scope)?;
6837 Ok(BindScope::RequestScope(scope))
6838 }
6839 what => {
6840 let mut builder = Report::build(ReportKind::Error, (), 0);
6841 let report = builder
6842 .with_message(format!(
6843 "Unrecognized BindConfig selector: '{}'",
6844 scope.selector.name.to_string()
6845 ))
6846 .with_label(
6847 Label::new(
6848 scope.selector.name.location_offset()
6849 ..scope.selector.name.location_offset() + scope.selector.name.len(),
6850 )
6851 .with_message("Unrecognized Selector"),
6852 )
6853 .finish();
6854 Err(ParseErrs::from_report(report, scope.block.content.extra().clone()).into())
6855 }
6856 }
6857}
6858
6859fn parse_bind_pipelines_scope<I: Span>(input: I) -> Result<Spanned<I, BindScopeKind>, ParseErrs> {
6860 unimplemented!()
6861 }
6891
6892pub fn nospace0<I: Span>(input: I) -> Res<I, I> {
6893 recognize(many0(satisfy(|c| !c.is_whitespace())))(input)
6894}
6895
6896pub fn nospace1<I: Span>(input: I) -> Res<I, I> {
6897 recognize(pair(
6898 satisfy(|c| !c.is_whitespace()),
6899 many0(satisfy(|c| !c.is_whitespace())),
6900 ))(input)
6901}
6902pub fn nospace1_nosemi<I: Span>(input: I) -> Res<I, I> {
6903 recognize(pair(
6904 satisfy(|c| !c.is_whitespace() && ';' != c),
6905 many0(satisfy(|c| !c.is_whitespace( ) && ';' != c)),
6906 ))(input)
6907}
6908
6909
6910
6911pub fn no_space_with_blocks<I: Span>(input: I) -> Res<I, I> {
6912 recognize(many1(alt((recognize(any_block), nospace1))))(input)
6913}
6914
6915pub fn pipeline_step_var<I: Span>(input: I) -> Res<I, PipelineStepVar> {
6916 context(
6917 "pipeline:step",
6918 tuple((
6919 alt((
6920 value(WaveDirection::Direct, tag("-")),
6921 value(WaveDirection::Reflect, tag("=")),
6922 )),
6923 opt(pair(
6924 delimited(
6925 tag("["),
6926 context("pipeline:step:exit", cut(request_payload_filter_block)),
6927 tag("]"),
6928 ),
6929 context(
6930 "pipeline:step:payload",
6931 cut(alt((
6932 value(WaveDirection::Direct, tag("-")),
6933 value(WaveDirection::Reflect, tag("=")),
6934 ))),
6935 ),
6936 )),
6937 context("pipeline:step:exit", cut(tag(">"))),
6938 )),
6939 )(input)
6940 .map(|(next, (entry, block_and_exit, _))| {
6941 let mut blocks = vec![];
6942 let exit = match block_and_exit {
6943 None => entry.clone(),
6944 Some((block, exit)) => {
6945 blocks.push(block);
6946 exit
6947 }
6948 };
6949
6950 (
6951 next,
6952 PipelineStepVar {
6953 entry,
6954 exit,
6955 blocks,
6956 },
6957 )
6958 })
6959}
6960
6961pub fn core_pipeline_stop<I: Span>(input: I) -> Res<I, PipelineStopVar> {
6962 context(
6963 "Core",
6964 delimited(
6965 tag("(("),
6966 delimited(multispace0, opt(tag("*")), multispace0),
6967 tag("))"),
6968 ),
6969 )(input)
6970 .map(|(next, _)| (next, PipelineStopVar::Core))
6971}
6972
6973pub fn return_pipeline_stop<I: Span>(input: I) -> Res<I, PipelineStopVar> {
6974 tag("&")(input).map(|(next, _)| (next, PipelineStopVar::Reflect))
6975}
6976
6977pub fn call_pipeline_stop<I: Span>(input: I) -> Res<I, PipelineStopVar> {
6978 context("Call", call)(input).map(|(next, call)| (next, PipelineStopVar::Call(call)))
6979}
6980
6981pub fn point_pipeline_stop<I: Span>(input: I) -> Res<I, PipelineStopVar> {
6982 context("pipeline:stop:point", point_var)(input)
6983 .map(|(next, point)| (next, PipelineStopVar::Point(point)))
6984}
6985
6986pub fn pipeline_stop_var<I: Span>(input: I) -> Res<I, PipelineStopVar> {
6987 context(
6988 "Stop",
6989 pair(
6990 context(
6991 "pipeline:stop:expecting",
6992 cut(peek(alt((tag("(("), tag("."), alpha1, tag("&"))))),
6993 ),
6994 alt((
6995 core_pipeline_stop,
6996 return_pipeline_stop,
6997 call_pipeline_stop,
6998 point_pipeline_stop,
6999 )),
7000 ),
7001 )(input)
7002 .map(|(next, (_, pipeline_stop))| (next, pipeline_stop))
7003}
7004
7005pub fn consume_pipeline_step<I: Span>(input: I) -> Res<I, PipelineStepVar> {
7006 all_consuming(pipeline_step_var)(input)
7007}
7008
7009pub fn consume_pipeline_stop<I: Span>(input: I) -> Res<I, PipelineStopVar> {
7010 all_consuming(pipeline_stop_var)(input)
7011}
7012
7013pub fn pipeline_segment<I: Span>(input: I) -> Res<I, PipelineSegmentVar> {
7014 tuple((
7015 multispace0,
7016 pipeline_step_var,
7017 multispace0,
7018 pipeline_stop_var,
7019 multispace0,
7020 ))(input)
7021 .map(|(next, (_, step, _, stop, _))| (next, PipelineSegmentVar { step, stop }))
7022}
7023
7024pub fn pipeline<I: Span>(input: I) -> Res<I, PipelineVar> {
7025 context(
7026 "pipeline",
7027 many0(delimited(multispace0, pipeline_segment, multispace0)),
7028 )(input)
7029 .map(|(next, segments)| (next, PipelineVar { segments }))
7030}
7031
7032pub fn consume_pipeline<I: Span>(input: I) -> Res<I, PipelineVar> {
7033 all_consuming(pipeline)(input)
7034}
7035
7036pub fn subst<I: Span, F>(f: F) -> impl FnMut(I) -> Res<I, Subst<I>>
7068where
7069 F: FnMut(I) -> Res<I, I> + Copy,
7070{
7071 move |input: I| {
7072 many1(chunk(f))(input.clone()).map(|(next, chunks)| {
7073 let len: usize = chunks.iter().map(|c| c.len()).sum();
7074 let span = input.slice(0..input.len() - next.len());
7075 let chunks = Subst {
7076 chunks,
7077 trace: span.trace(),
7078 };
7079 (next, chunks)
7080 })
7081 }
7082}
7083
7084pub fn chunk<I: Span, F>(mut f: F) -> impl FnMut(I) -> Res<I, Chunk<I>> + Copy
7085where
7086 F: FnMut(I) -> Res<I, I> + Copy,
7087{
7088 move |input: I| alt((var_chunk, text_chunk(f)))(input)
7089}
7090
7091pub fn text_chunk<I: Span, F>(mut f: F) -> impl FnMut(I) -> Res<I, Chunk<I>> + Copy
7092where
7093 F: FnMut(I) -> Res<I, I> + Copy,
7094{
7095 move |input: I| f(input).map(|(next, text)| (next, Chunk::Text(text)))
7096}
7097
7098pub fn var_chunk<I: Span>(input: I) -> Res<I, Chunk<I>> {
7099 preceded(
7100 tag("$"),
7101 context(
7102 "variable",
7103 cut(delimited(
7104 context("variable:open", cut(tag("{"))),
7105 context("variable:name", variable_name),
7106 context("variable:close", cut(tag("}"))),
7107 )),
7108 ),
7109 )(input)
7110 .map(|(next, variable_name)| (next, Chunk::Var(variable_name)))
7111}
7112pub fn route_attribute(input: &str) -> Result<RouteSelector, SpaceErr> {
7120 let input = new_span(input);
7121 let (_, (_, lex_route)) = result(pair(
7122 tag("#"),
7123 unwrap_block(
7124 BlockKind::Nested(NestedBlockKind::Square),
7125 pair(
7126 tag("route"),
7127 unwrap_block(
7128 BlockKind::Nested(NestedBlockKind::Parens),
7129 unwrap_block(
7130 BlockKind::Delimited(DelimitedBlockKind::DoubleQuotes),
7131 nospace0,
7132 ),
7133 ),
7134 ),
7135 ),
7136 )(input.clone()))?;
7137
7138 route_selector(lex_route)
7139}
7140
7141pub fn route_attribute_value(input: &str) -> Result<RouteSelector, SpaceErr> {
7142 let input = new_span(input);
7143 let lex_route = result(unwrap_block(
7144 BlockKind::Delimited(DelimitedBlockKind::DoubleQuotes),
7145 trim(nospace0),
7146 )(input.clone()))?;
7147
7148 route_selector(lex_route)
7149}
7150
7151pub fn route_selector<I: Span>(input: I) -> Result<RouteSelector, SpaceErr> {
7170 let (next, (topic, lex_route)) = match pair(
7171 opt(terminated(
7172 unwrap_block(
7173 BlockKind::Nested(NestedBlockKind::Square),
7174 value_pattern(topic),
7175 ),
7176 tag("::"),
7177 )),
7178 lex_route_selector,
7179 )(input.clone())
7180 {
7181 Ok((next, (topic, lex_route))) => (next, (topic, lex_route)),
7182 Err(err) => {
7183 return Err(find_parse_err(&err));
7184 }
7185 };
7186
7187 if next.len() > 0 {
7188 return Err(ParseErrs::from_loc_span(
7189 "could not consume entire route selector",
7190 "extra",
7191 next,
7192 )
7193 .into());
7194 }
7195
7196 let mut names = lex_route.names.clone();
7197 names.reverse();
7198 let method_kind_span = names
7199 .pop()
7200 .ok_or(ParseErrs::from_loc_span(
7201 "expecting MethodKind [ Http, Ext ]",
7202 "expecting MethodKind",
7203 input,
7204 ))?
7205 .clone();
7206 let method_kind = result(value_pattern(method_kind)(method_kind_span.clone()))?;
7207 let method = match &method_kind {
7208 ValuePattern::Any => ValuePattern::Any,
7209 ValuePattern::None => ValuePattern::None,
7210 ValuePattern::Pattern(method_kind) => match method_kind {
7211 MethodKind::Hyp => {
7212 let method = names.pop().ok_or(ParseErrs::from_loc_span(
7213 "Hyp method requires a sub kind i.e. Hyp<Assign> or Ext<*>",
7214 "sub kind required",
7215 method_kind_span,
7216 ))?;
7217 let method = result(value_pattern(sys_method)(method))?;
7218 ValuePattern::Pattern(MethodPattern::Hyp(method))
7219 }
7220 MethodKind::Cmd => {
7221 let method = names.pop().ok_or(ParseErrs::from_loc_span(
7222 "Cmd method requires a sub kind i.e. Cmd<Bounce>",
7223 "sub kind required",
7224 method_kind_span,
7225 ))?;
7226 let method = result(value_pattern(cmd_method)(method))?;
7227 ValuePattern::Pattern(MethodPattern::Cmd(method))
7228 }
7229 MethodKind::Ext => {
7230 let method = names.pop().ok_or(ParseErrs::from_loc_span(
7231 "Ext method requires a sub kind i.e. Ext<SomeExt> or Ext<*>",
7232 "sub kind required",
7233 method_kind_span,
7234 ))?;
7235 let method = result(value_pattern(ext_method)(method))?;
7236 ValuePattern::Pattern(MethodPattern::Ext(method))
7237 }
7238 MethodKind::Http => {
7239 let method = names.pop().ok_or(ParseErrs::from_loc_span(
7240 "Http method requires a sub kind i.e. Http<Get> or Http<*>",
7241 "sub kind required",
7242 method_kind_span,
7243 ))?;
7244 let method = result(value_pattern(http_method)(method))?;
7245 ValuePattern::Pattern(MethodPattern::Http(method))
7246 }
7247 },
7248 };
7249
7250 if !names.is_empty() {
7251 let name = names.pop().unwrap();
7252 return Err(ParseErrs::from_loc_span("Too many SubKinds: only Http/Ext supported with one subkind i.e. Http<Get>, Ext<MyMethod>", "too many subkinds", name).into());
7253 }
7254
7255 let path = match lex_route.path.as_ref() {
7256 None => Regex::new("/.*").unwrap(),
7257 Some(i) => match Regex::new(i.to_string().as_str()) {
7258 Ok(path) => path,
7259 Err(err) => {
7260 return Err(ParseErrs::from_loc_span(
7261 format!("cannot parse Path regex: '{}'", err.to_string()).as_str(),
7262 "path regex error",
7263 i.clone(),
7264 ));
7265 }
7266 },
7267 };
7268
7269 Ok(RouteSelector::new(
7270 topic,
7271 method,
7272 path,
7273 lex_route.filters.to_scope_filters(),
7274 ))
7275}
7276
7277#[cfg(test)]
7278pub mod test {
7279 use std::rc::Rc;
7280 use std::str::FromStr;
7281 use std::sync::Arc;
7282
7283 use bincode::config;
7284 use nom::branch::alt;
7285 use nom::bytes::complete::{escaped, tag};
7286 use nom::character::complete::{alpha1, alphanumeric1, anychar, multispace0};
7287 use nom::character::is_alphanumeric;
7288 use nom::combinator::{all_consuming, eof, not, opt, peek, recognize};
7289 use nom::error::context;
7290 use nom::multi::{many0, many1};
7291 use nom::sequence::{delimited, pair, terminated, tuple};
7292 use nom::IResult;
7293 use nom_locate::LocatedSpan;
7294 use nom_supreme::error::ErrorTree;
7295
7296 use cosmic_nom::{new_span, Res, span_with_extra};
7297
7298 use crate::command::direct::create::{
7299 PointSegTemplate, PointTemplate, PointTemplateCtx, Template,
7300 };
7301 use crate::command::Command;
7302 use crate::config::Document;
7303 use crate::err::{ParseErrs, SpaceErr};
7304 use crate::parse::error::result;
7305 use crate::parse::model::{
7306 BlockKind, DelimitedBlockKind, LexScope, NestedBlockKind, TerminatedBlockKind,
7307 };
7308 use crate::parse::{args, assignment, base_point_segment, base_seg, command_line, comment, consume_point_var, create, create_command, doc, Env, expected_block_terminator_or_non_terminator, lex_block, lex_child_scopes, lex_nested_block, lex_scope, lex_scope_pipeline_step_and_block, lex_scope_selector, lex_scopes, lowercase1, MapResolver, mesh_eos, mesh_seg, nested_block, nested_block_content, next_stacked_name, no_comment, parse_bind_config, parse_include_blocks, parse_inner_block, parse_mechtron_config, path_regex, pipeline, pipeline_segment, pipeline_step_var, pipeline_stop_var, point_non_root_var, point_template, point_var, pop, rec_version, root_ctx_seg, root_scope, root_scope_selector, route_attribute, route_selector, scope_filter, scope_filters, skewer_case_chars, skewer_dot, space_chars, space_no_dupe_dots, space_point_segment, strip_comments, subst, SubstParser, template, var_seg, variable_name, VarResolver, version, version_point_segment, wrapper};
7309 use crate::point::{Point, PointCtx, PointSegVar, RouteSegVar};
7310 use crate::substance::Substance;
7311 use crate::util;
7312 use crate::util::{log, ToResolved};
7313
7314 #[test]
7315 pub fn test_assignment() {
7316 let config = "+bin=some:bin:somewhere;";
7317 let assign = log(result(assignment(new_span(config)))).unwrap();
7318 assert_eq!(assign.key.as_str(), "bin");
7319 assert_eq!(assign.value.as_str(), "some:bin:somewhere");
7320
7321 let config = " +bin = some:bin:somewhere;";
7322 log(result(assignment(new_span(config)))).unwrap();
7323
7324 let config = " noplus = some:bin:somewhere;";
7325 assert!(log(result(assignment(new_span(config)))).is_err());
7326 let config = " +nothing ";
7327 assert!(log(result(assignment(new_span(config)))).is_err());
7328 let config = " +nothing = ";
7329 assert!(log(result(assignment(new_span(config)))).is_err());
7330
7331 }
7332
7333
7334 #[test]
7335 pub fn test_mechtron_config() {
7336 let config = r#"
7337
7338Mechtron(version=1.0.0) {
7339 Wasm {
7340 +bin=repo:1.0.0:/wasm/blah.wasm;
7341 +name=my-mechtron;
7342 }
7343}
7344
7345 "#;
7346
7347 let doc = log(doc(config)).unwrap();
7348
7349 if let Document::MechtronConfig(_) = doc {
7350 } else {
7351 assert!(false)
7352 }
7353 }
7354
7355
7356
7357 #[test]
7358 pub fn test_bad_mechtron_config() {
7359 let config = r#"
7360
7361Mechtron(version=1.0.0) {
7362 Wasm
7363 varool
7364 +bin=repo:1.0.0:/wasm/blah.wasm;
7365 +name=my-mechtron;
7366 }
7367}
7368
7369 "#;
7370
7371 let doc = log(doc(config)).is_err();
7372
7373
7374 }
7375
7376
7377 #[test]
7378 pub fn test_message_selector() {
7379 let route =
7380 util::log(route_attribute("#[route(\"[Topic<*>]::Ext<NewSession>\")]")).unwrap();
7381 let route = util::log(route_attribute("#[route(\"Hyp<Assign>\")]")).unwrap();
7382
7383 println!("path: {}", route.path.to_string());
7384 }
7386
7387 #[test]
7388 pub fn test_create_command() -> Result<(), SpaceErr> {
7389 let command = util::log(result(command_line(new_span("create localhost<Space>"))))?;
7390 let env = Env::new(Point::root());
7391 let command: Command = util::log(command.to_resolved(&env))?;
7392 Ok(())
7393 }
7394
7395pub fn test_command_line_err() -> Result<(), SpaceErr> {
7397 let command = util::log(result(command_line(new_span("create localhost<bad>"))))?;
7398 let env = Env::new(Point::root());
7399 let command: Command = util::log(command.to_resolved(&env))?;
7400 Ok(())
7401 }
7402
7403 #[test]
7404 pub fn test_template() -> Result<(), SpaceErr> {
7405 let t = util::log(result(all_consuming(template)(new_span(
7406 "localhost<Space>",
7407 ))))?;
7408 let env = Env::new(Point::root());
7409 let t: Template = util::log(t.to_resolved(&env))?;
7410
7411 let t = util::log(result(base_point_segment(new_span(
7412 "localhost:base<Space>",
7413 ))))?;
7414
7415 let (space, bases): (PointSegVar, Vec<PointSegVar>) = util::log(result(tuple((
7416 var_seg(root_ctx_seg(space_point_segment)),
7417 many0(base_seg(var_seg(pop(base_point_segment)))),
7418 ))(
7419 new_span("localhost:base:nopo<Space>"),
7420 )))?;
7421 println!("space: {}", space.to_string());
7422 for base in bases {
7423 println!("\tbase: {}", base.to_string());
7424 }
7425 Ok(())
7430 }
7431
7432 #[test]
7433 pub fn test_point_template() -> Result<(), SpaceErr> {
7434 assert!(mesh_eos(new_span(":")).is_ok());
7435 assert!(mesh_eos(new_span("%")).is_ok());
7436 assert!(mesh_eos(new_span("x")).is_err());
7437
7438 assert!(point_var(new_span("localhost:some-%")).is_ok());
7439
7440 util::log(result(all_consuming(point_template)(new_span("localhost"))))?;
7441
7442 let template = util::log(result(point_template(new_span("localhost:other:some-%"))))?;
7443 let template: PointTemplate = util::log(template.collapse())?;
7444 if let PointSegTemplate::Pattern(child) = template.child_segment_template {
7445 assert_eq!(child.as_str(), "some-%")
7446 }
7447
7448 util::log(result(point_template(new_span("my-domain.com"))))?;
7449 util::log(result(point_template(new_span("ROOT"))))?;
7450 Ok(())
7451 }
7452
7453 pub fn test_point_var() -> Result<(), SpaceErr> {
7455 util::log(result(all_consuming(point_var)(new_span(
7456 "[hub]::my-domain.com:${name}:base",
7457 ))))?;
7458 util::log(result(all_consuming(point_var)(new_span(
7459 "[hub]::my-domain.com:1.0.0:/dorko/x/",
7460 ))))?;
7461 util::log(result(all_consuming(point_var)(new_span(
7462 "[hub]::my-domain.com:1.0.0:/dorko/${x}/",
7463 ))))?;
7464 util::log(result(all_consuming(point_var)(new_span(
7465 "[hub]::.:1.0.0:/dorko/${x}/",
7466 ))))?;
7467 util::log(result(all_consuming(point_var)(new_span(
7468 "[hub]::..:1.0.0:/dorko/${x}/",
7469 ))))?;
7470 let point = util::log(result(point_var(new_span(
7471 "[hub]::my-domain.com:1.0.0:/dorko/${x}/file.txt",
7472 ))))?;
7473 if let Some(PointSegVar::Var(var)) = point.segments.get(4) {
7474 assert_eq!("x", var.name.as_str());
7475 } else {
7476 assert!(false);
7477 }
7478
7479 if let Some(PointSegVar::File(file)) = point.segments.get(5) {
7480 assert_eq!("file.txt", file.as_str());
7481 } else {
7482 assert!(false);
7483 }
7484
7485 let point = util::log(result(point_var(new_span(
7486 "${route}::my-domain.com:${name}:base",
7487 ))))?;
7488
7489 util::log(result(point_var(new_span(
7491 "${route of routes}::my-domain.com:${BAD}:base",
7492 ))));
7493
7494 if let RouteSegVar::Var(ref var) = point.route {
7495 assert_eq!("route", var.name.as_str());
7496 } else {
7497 assert!(false);
7498 }
7499
7500 if let Some(PointSegVar::Space(space)) = point.segments.get(0) {
7501 assert_eq!("my-domain.com", space.as_str());
7502 } else {
7503 assert!(false);
7504 }
7505
7506 if let Some(PointSegVar::Var(var)) = point.segments.get(1) {
7507 assert_eq!("name", var.name.as_str());
7508 } else {
7509 assert!(false);
7510 }
7511
7512 if let Some(PointSegVar::Base(base)) = point.segments.get(2) {
7513 assert_eq!("base", base.as_str());
7514 } else {
7515 assert!(false);
7516 }
7517
7518 let mut env = Env::new(Point::from_str("my-domain.com")?);
7519 env.set_var("route", Substance::Text("[hub]".to_string()));
7520 env.set_var("name", Substance::Text("zophis".to_string()));
7521 let point: Point = point.to_resolved(&env)?;
7522 println!("point.to_string(): {}", point.to_string());
7523
7524 util::log(
7525 util::log(result(all_consuming(point_var)(new_span(
7526 "[hub]::my-domain.com:1.0.0:/dorko/x/",
7527 ))))?
7528 .to_point(),
7529 );
7530 util::log(
7531 util::log(result(all_consuming(point_var)(new_span(
7532 "[hub]::my-domain.com:1.0.0:/${dorko}/x/",
7533 ))))?
7534 .to_point(),
7535 );
7536 util::log(
7537 util::log(result(all_consuming(point_var)(new_span(
7538 "${not-supported}::my-domain.com:1.0.0:/${dorko}/x/",
7539 ))))?
7540 .to_point(),
7541 );
7542
7543 let point = util::log(result(point_var(new_span("${route}::${root}:base1"))))?;
7544 let mut env = Env::new(Point::from_str("my-domain.com:blah")?);
7545 env.set_var("route", Substance::Text("[hub]".to_string()));
7546 env.set_var("root", Substance::Text("..".to_string()));
7547
7548 let point: PointCtx = util::log(point.to_resolved(&env))?;
7549
7550 Ok(())
7562 }
7563
7564 #[test]
7565 pub fn test_point() -> Result<(), SpaceErr> {
7566 util::log(
7567 result(all_consuming(point_var)(new_span(
7568 "[hub]::my-domain.com:name:base",
7569 )))?
7570 .to_point(),
7571 )?;
7572 util::log(
7573 result(all_consuming(point_var)(new_span(
7574 "[hub]::my-domain.com:1.0.0:/dorko/x/",
7575 )))?
7576 .to_point(),
7577 )?;
7578 util::log(
7579 result(all_consuming(point_var)(new_span(
7580 "[hub]::my-domain.com:1.0.0:/dorko/xyz/",
7581 )))?
7582 .to_point(),
7583 )?;
7584
7585 Ok(())
7586 }
7587
7588 #[test]
7589 pub fn test_simple_point_var() -> Result<(), SpaceErr> {
7590 let point = util::log(result(point_var(new_span(
7615 "localhost:base:/fs/file.txt<Kind>",
7616 ))))?;
7617 let point: Point = point.collapse()?;
7618 assert_eq!("localhost:base:/fs/file.txt", point.to_string().as_str());
7619
7620 Ok(())
7621 }
7622
7623 #[test]
7624 pub fn test_lex_block() -> Result<(), SpaceErr> {
7625 let esc = result(escaped(anychar, '\\', anychar)(new_span("\\}")))?;
7626 util::log(result(all_consuming(lex_block(BlockKind::Nested(
7628 NestedBlockKind::Curly,
7629 )))(new_span("{}"))))?;
7630 util::log(result(all_consuming(lex_block(BlockKind::Nested(
7631 NestedBlockKind::Curly,
7632 )))(new_span("{x}"))))?;
7633 util::log(result(all_consuming(lex_block(BlockKind::Nested(
7634 NestedBlockKind::Curly,
7635 )))(new_span("{\\}}"))))?;
7636 util::log(result(all_consuming(lex_block(BlockKind::Delimited(
7637 DelimitedBlockKind::SingleQuotes,
7638 )))(new_span("'hello'"))))?;
7639 util::log(result(all_consuming(lex_block(BlockKind::Delimited(
7640 DelimitedBlockKind::SingleQuotes,
7641 )))(new_span("'ain\\'t it cool?'"))))?;
7642
7643 Ok(())
7645 }
7646 #[test]
7647 pub fn test_path_regex2() -> Result<(), SpaceErr> {
7648 util::log(result(path_regex(new_span("/xyz"))))?;
7649 Ok(())
7650 }
7651 #[test]
7652 pub fn test_bind_config() -> Result<(), SpaceErr> {
7653 let bind_config_str = r#"Bind(version=1.0.0) { Route<Http> -> { <Get> -> ((*)) => &; } }
7654 "#;
7655
7656 util::log(doc(bind_config_str))?;
7657 if let Document::BindConfig(bind) = util::log(doc(bind_config_str))? {
7658 assert_eq!(bind.route_scopes().len(), 1);
7659 let mut pipelines = bind.route_scopes();
7660 let pipeline_scope = pipelines.pop().unwrap();
7661 assert_eq!(pipeline_scope.selector.selector.name.as_str(), "Route");
7662 let message_scope = pipeline_scope.block.first().unwrap();
7663 assert_eq!(
7664 message_scope.selector.selector.name.to_string().as_str(),
7665 "Http"
7666 );
7667 let method_scope = message_scope.block.first().unwrap();
7668 assert_eq!(
7669 method_scope.selector.selector.name.to_string().as_str(),
7670 "Http<Get>"
7671 );
7672 } else {
7673 assert!(false);
7674 }
7675
7676 let bind_config_str = r#"Bind(version=1.0.0) {
7677 Route<Ext<Create>> -> localhost:app => &;
7678 }"#;
7679
7680 if let Document::BindConfig(bind) = util::log(doc(bind_config_str))? {
7681 assert_eq!(bind.route_scopes().len(), 1);
7682 let mut pipelines = bind.route_scopes();
7683 let pipeline_scope = pipelines.pop().unwrap();
7684 assert_eq!(pipeline_scope.selector.selector.name.as_str(), "Route");
7685 let message_scope = pipeline_scope.block.first().unwrap();
7686 assert_eq!(
7687 message_scope.selector.selector.name.to_string().as_str(),
7688 "Ext"
7689 );
7690 let action_scope = message_scope.block.first().unwrap();
7691 assert_eq!(
7692 action_scope.selector.selector.name.to_string().as_str(),
7693 "Ext<Create>"
7694 );
7695 } else {
7696 assert!(false);
7697 }
7698
7699 let bind_config_str = r#" Bind(version=1.0.0) {
7700 Route -> {
7701 <*> -> {
7702 <Get>/users/(?P<user>)/.* -> localhost:users:${user} => &;
7703 }
7704 }
7705 }
7706
7707 "#;
7708 util::log(doc(bind_config_str))?;
7709
7710 let bind_config_str = r#" Bind(version=1.0.0) {
7711 Route -> {
7712 <Http<*>>/users -> localhost:users => &;
7713 }
7714 }
7715
7716 "#;
7717 util::log(doc(bind_config_str))?;
7718
7719 let bind_config_str = r#" Bind(version=1.0.0) {
7720 * -> { // This should fail since Route needs to be defined
7721 <*> -> {
7722 <Get>/users -> localhost:users => &;
7723 }
7724 }
7725 }
7726
7727 "#;
7728 assert!(util::log(doc(bind_config_str)).is_err());
7729 let bind_config_str = r#" Bind(version=1.0.0) {
7730 Route<Rc> -> {
7731 Create ; Bok;
7732 }
7733 }
7734
7735 "#;
7736 assert!(util::log(doc(bind_config_str)).is_err());
7737 Ok(())
7740 }
7741
7742 #[test]
7743 pub fn test_pipeline_segment() -> Result<(), SpaceErr> {
7744 util::log(result(pipeline_segment(new_span("-> localhost"))))?;
7745 assert!(util::log(result(pipeline_segment(new_span("->")))).is_err());
7746 assert!(util::log(result(pipeline_segment(new_span("localhost")))).is_err());
7747 Ok(())
7748 }
7749
7750 #[test]
7751 pub fn test_pipeline_stop() -> Result<(), SpaceErr> {
7752 util::log(result(space_chars(new_span("localhost"))))?;
7753 util::log(result(space_no_dupe_dots(new_span("localhost"))))?;
7754
7755 util::log(result(mesh_eos(new_span(""))))?;
7756 util::log(result(mesh_eos(new_span(":"))))?;
7757
7758 util::log(result(recognize(tuple((
7759 context("point:space_segment_leading", peek(alpha1)),
7760 space_no_dupe_dots,
7761 space_chars,
7762 )))(new_span("localhost"))))?;
7763 util::log(result(space_point_segment(new_span("localhost.com"))))?;
7764
7765 util::log(result(point_var(new_span("mechtron.io:app:hello")))?.to_point())?;
7766 util::log(result(pipeline_stop_var(new_span("localhost:app:hello"))))?;
7767 Ok(())
7768 }
7769
7770 #[test]
7771 pub fn test_pipeline() -> Result<(), SpaceErr> {
7772 util::log(result(pipeline(new_span("-> localhost => &"))))?;
7773 Ok(())
7774 }
7775
7776 #[test]
7777 pub fn test_pipeline_step() -> Result<(), SpaceErr> {
7778 util::log(result(pipeline_step_var(new_span("->"))))?;
7779 util::log(result(pipeline_step_var(new_span("-[ Text ]->"))))?;
7780 util::log(result(pipeline_step_var(new_span("-[ Text ]=>"))))?;
7781 util::log(result(pipeline_step_var(new_span("=[ Text ]=>"))))?;
7782
7783 assert!(util::log(result(pipeline_step_var(new_span("=")))).is_err());
7784 assert!(util::log(result(pipeline_step_var(new_span("-[ Bin ]=")))).is_err());
7785 assert!(util::log(result(pipeline_step_var(new_span("[ Bin ]=>")))).is_err());
7786 Ok(())
7787 }
7788
7789 #[test]
7790 pub fn test_rough_bind_config() -> Result<(), SpaceErr> {
7791 let unknown_config_kind = r#"
7792Unknown(version=1.0.0) # mem unknown config kind
7793{
7794 Route{
7795 }
7796}"#;
7797 let unsupported_bind_version = r#"
7798Bind(version=100.0.0) # mem unsupported version
7799{
7800 Route{
7801 }
7802}"#;
7803 let multiple_unknown_sub_selectors = r#"
7804Bind(version=1.0.0)
7805{
7806 Whatever -> { # Someone doesn't care what sub selectors he creates
7807 }
7808
7809 Dude(filter $(value)) -> {} # he doesn't care one bit!
7810
7811}"#;
7812
7813 let now_we_got_rows_to_parse = r#"
7814Bind(version=1.0.0)
7815{
7816 Route(auth) -> {
7817 Http {
7818 <$(method=.*)>/users/$(user=.*)/$(path=.*)-> localhost:app:users:$(user)^Http<$(method)>/$(path) => &;
7819 <Get>/logout -> localhost:app:mechtrons:logout-handler => &;
7820 }
7821 }
7822
7823 Route -> {
7824 Ext<FullStop> -> localhost:apps:
7825 * -> localhost:app:bad-page => &;
7826 }
7827
7828
7829}"#;
7830 util::log(doc(unknown_config_kind));
7831 util::log(doc(unsupported_bind_version));
7832 util::log(doc(multiple_unknown_sub_selectors));
7833 util::log(doc(now_we_got_rows_to_parse));
7834
7835 Ok(())
7836 }
7837
7838 #[test]
7839 pub fn test_remove_comments() -> Result<(), SpaceErr> {
7840 let bind_str = r#"
7841# this is a mem of comments
7842Bind(version=1.0.0)->
7843{
7844 # let's see if it works a couple of spaces in.
7845 Route(auth)-> { # and if it works on teh same line as something we wan to keep
7846
7847 }
7848
7849 # looky! I deliberatly put an error here (space between the filter and the kazing -> )
7850 # My hope is that we will get a an appropriate error message WITH COMMENTS INTACT
7851 Route(noauth)-> # look! I made a boo boo
7852 {
7853 # nothign to see here
7854 }
7855}"#;
7856
7857 match doc(bind_str) {
7858 Ok(_) => {}
7859 Err(err) => {
7860 err.print();
7861 }
7862 }
7863
7864 Ok(())
7865 }
7866
7867 #[test]
7868 pub fn test_version() -> Result<(), SpaceErr> {
7869 rec_version(new_span("1.0.0"))?;
7870 rec_version(new_span("1.0.0-alpha"))?;
7871 version(new_span("1.0.0-alpha"))?;
7872
7873 Ok(())
7874 }
7875 #[test]
7876 pub fn test_rough_block() -> Result<(), SpaceErr> {
7877 result(all_consuming(lex_nested_block(NestedBlockKind::Curly))(
7878 new_span("{ }"),
7879 ))?;
7880 result(all_consuming(lex_nested_block(NestedBlockKind::Curly))(
7881 new_span("{ {} }"),
7882 ))?;
7883 assert!(
7884 result(all_consuming(lex_nested_block(NestedBlockKind::Curly))(
7885 new_span("{ } }")
7886 ))
7887 .is_err()
7888 );
7889 result(all_consuming(lex_nested_block(NestedBlockKind::Curly))(
7891 new_span("{ ] }"),
7892 ))?;
7893
7894 result(lex_nested_block(NestedBlockKind::Curly)(new_span(
7895 r#"x blah
7896
7897
7898Hello my friend
7899
7900
7901 }"#,
7902 )))
7903 .err()
7904 .unwrap()
7905 .print();
7906
7907 result(lex_nested_block(NestedBlockKind::Curly)(new_span(
7908 r#"{
7909
7910Hello my friend
7911
7912
7913 "#,
7914 )))
7915 .err()
7916 .unwrap()
7917 .print();
7918 Ok(())
7919 }
7920
7921 #[test]
7922 pub fn test_block() -> Result<(), SpaceErr> {
7923 util::log(result(lex_nested_block(NestedBlockKind::Curly)(new_span(
7924 "{ <Get> -> localhost; } ",
7925 ))))?;
7926 if true {
7927 return Ok(());
7928 }
7929 all_consuming(nested_block(NestedBlockKind::Curly))(new_span("{ }"))?;
7930 all_consuming(nested_block(NestedBlockKind::Curly))(new_span("{ {} }"))?;
7931 util::log(result(nested_block(NestedBlockKind::Curly)(new_span(
7932 "{ [] }",
7933 ))))?;
7934 assert!(
7935 expected_block_terminator_or_non_terminator(NestedBlockKind::Curly)(new_span("}"))
7936 .is_ok()
7937 );
7938 assert!(
7939 expected_block_terminator_or_non_terminator(NestedBlockKind::Curly)(new_span("]"))
7940 .is_err()
7941 );
7942 assert!(
7943 expected_block_terminator_or_non_terminator(NestedBlockKind::Square)(new_span("x"))
7944 .is_ok()
7945 );
7946 assert!(nested_block(NestedBlockKind::Curly)(new_span("{ ] }")).is_err());
7947 result(nested_block(NestedBlockKind::Curly)(new_span(
7948 r#"{
7949
7950
7951
7952 ]
7953
7954
7955 }"#,
7956 )))
7957 .err()
7958 .unwrap()
7959 .print();
7960 Ok(())
7961 }
7962
7963 pub fn test_root_scope_selector() -> Result<(), SpaceErr> {
7965 assert!(
7966 (result(root_scope_selector(new_span(
7967 r#"
7968
7969 Bind(version=1.0.0)->"#,
7970 )))
7971 .is_ok())
7972 );
7973
7974 assert!(
7975 (result(root_scope_selector(new_span(
7976 r#"
7977
7978 Bind(version=1.0.0-alpha)->"#,
7979 )))
7980 .is_ok())
7981 );
7982
7983 result(root_scope_selector(new_span(
7984 r#"
7985
7986 Bind(version=1.0.0) ->"#,
7987 )))
7988 .err()
7989 .unwrap()
7990 .print();
7991
7992 result(root_scope_selector(new_span(
7993 r#"
7994
7995 Bind x"#,
7996 )))
7997 .err()
7998 .unwrap()
7999 .print();
8000
8001 result(root_scope_selector(new_span(
8002 r#"
8003
8004 (Bind(version=3.2.0) "#,
8005 )))
8006 .err()
8007 .unwrap()
8008 .print();
8009
8010 Ok(())
8011 }
8012
8013 pub fn test_scope_filter() -> Result<(), SpaceErr> {
8015 result(scope_filter(new_span("(auth)")))?;
8016 result(scope_filter(new_span("(auth )")))?;
8017 result(scope_filter(new_span("(auth hello)")))?;
8018 result(scope_filter(new_span("(auth +hello)")))?;
8019 result(scope_filters(new_span("(auth +hello)->")))?;
8020 result(scope_filters(new_span("(auth +hello)-(filter2)->")))?;
8021 result(scope_filters(new_span("(3auth +hello)-(filter2)->")))
8022 .err()
8023 .unwrap()
8024 .print();
8025 result(scope_filters(new_span("(a?th +hello)-(filter2)->")))
8026 .err()
8027 .unwrap()
8028 .print();
8029 result(scope_filters(new_span("(auth +hello)-(filter2) {}")))
8030 .err()
8031 .unwrap()
8032 .print();
8033
8034 assert!(skewer_case_chars(new_span("3x")).is_err());
8035
8036 Ok(())
8037 }
8038 #[test]
8039 pub fn test_next_selector() {
8040 assert_eq!(
8041 "Http",
8042 next_stacked_name(new_span("Http"))
8043 .unwrap()
8044 .1
8045 .0
8046 .to_string()
8047 .as_str()
8048 );
8049 assert_eq!(
8050 "Http",
8051 next_stacked_name(new_span("<Http>"))
8052 .unwrap()
8053 .1
8054 .0
8055 .to_string()
8056 .as_str()
8057 );
8058 assert_eq!(
8059 "Http",
8060 next_stacked_name(new_span("Http<Ext>"))
8061 .unwrap()
8062 .1
8063 .0
8064 .to_string()
8065 .as_str()
8066 );
8067 assert_eq!(
8068 "Http",
8069 next_stacked_name(new_span("<Http<Ext>>"))
8070 .unwrap()
8071 .1
8072 .0
8073 .to_string()
8074 .as_str()
8075 );
8076
8077 assert_eq!(
8078 "*",
8079 next_stacked_name(new_span("<*<Ext>>"))
8080 .unwrap()
8081 .1
8082 .0
8083 .to_string()
8084 .as_str()
8085 );
8086
8087 assert_eq!(
8088 "*",
8089 next_stacked_name(new_span("*"))
8090 .unwrap()
8091 .1
8092 .0
8093 .to_string()
8094 .as_str()
8095 );
8096
8097 assert!(next_stacked_name(new_span("<*x<Ext>>")).is_err());
8098 }
8099 #[test]
8100 pub fn test_lex_scope2() -> Result<(), SpaceErr> {
8101 util::log(result(many0(delimited(
8107 multispace0,
8108 lex_scope,
8109 multispace0,
8110 ))(new_span(""))))?;
8111 util::log(result(path_regex(new_span("/root/$(subst)"))))?;
8112 util::log(result(path_regex(new_span("/users/$(user=.*)"))))?;
8113
8114 Ok(())
8115 }
8116
8117 #[test]
8118 pub fn test_lex_scope() -> Result<(), SpaceErr> {
8119 let pipes = util::log(result(lex_scope(new_span("Pipes -> {}")))).unwrap();
8120
8121 assert_eq!(pipes.selector.name.to_string().as_str(), "Pipes");
8124 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8125 assert_eq!(pipes.block.content.len(), 0);
8126 assert!(pipes.selector.filters.is_empty());
8127 assert!(pipes.pipeline_step.is_some());
8128
8129 assert!(util::log(result(lex_scope(new_span("Pipes {}")))).is_err());
8130
8131 let pipes = util::log(result(lex_scope(new_span("Pipes -> 12345;"))))?;
8132 assert_eq!(pipes.selector.name.to_string().as_str(), "Pipes");
8133 assert_eq!(pipes.block.content.to_string().as_str(), "-> 12345");
8134 assert_eq!(
8135 pipes.block.kind,
8136 BlockKind::Terminated(TerminatedBlockKind::Semicolon)
8137 );
8138 assert_eq!(pipes.selector.filters.len(), 0);
8139 assert!(pipes.pipeline_step.is_none());
8140 let pipes = util::log(result(lex_scope(new_span(
8141 r#"Pipes -> 12345;"#,
8143 ))))?;
8144 assert_eq!(pipes.selector.name.to_string().as_str(), "Pipes");
8145 assert_eq!(pipes.block.content.to_string().as_str(), "-> 12345");
8146 assert_eq!(
8147 pipes.block.kind,
8148 BlockKind::Terminated(TerminatedBlockKind::Semicolon)
8149 );
8150 assert_eq!(pipes.selector.filters.len(), 0);
8151 assert!(pipes.pipeline_step.is_none());
8152
8153 let pipes = util::log(result(lex_scope(new_span("Pipes(auth) -> {}"))))?;
8154
8155 assert_eq!(pipes.selector.name.to_string().as_str(), "Pipes");
8156 assert_eq!(pipes.block.content.len(), 0);
8157 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8158 assert_eq!(pipes.selector.filters.len(), 1);
8159 assert!(pipes.pipeline_step.is_some());
8160
8161 let pipes = util::log(result(lex_scope(new_span("Route<Ext> -> {}"))))?;
8162
8163 assert_eq!(pipes.selector.name.to_string().as_str(), "Route");
8164 assert_eq!(
8165 Some(
8166 pipes
8167 .selector
8168 .children
8169 .as_ref()
8170 .unwrap()
8171 .to_string()
8172 .as_str()
8173 ),
8174 Some("<Ext>")
8175 );
8176
8177 assert_eq!(pipes.block.content.to_string().as_str(), "");
8178 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8179 assert_eq!(pipes.selector.filters.len(), 0);
8180 assert!(pipes.pipeline_step.is_some());
8181
8182 let pipes = util::log(result(lex_scope(new_span(
8183 "Route<Http>(noauth) -> {zoink!{}}",
8184 ))))?;
8185 assert_eq!(pipes.selector.name.to_string().as_str(), "Route");
8186 assert_eq!(
8187 Some(
8188 pipes
8189 .selector
8190 .children
8191 .as_ref()
8192 .unwrap()
8193 .to_string()
8194 .as_str()
8195 ),
8196 Some("<Http>")
8197 );
8198 assert_eq!(pipes.block.content.to_string().as_str(), "zoink!{}");
8199 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8200 assert_eq!(pipes.selector.filters.len(), 1);
8201 let msg = "Hello my future friend";
8204 let parseme = format!("<Http<Get>> -> {};", msg);
8205 let pipes = util::log(result(lex_scope(new_span(parseme.as_str()))))?;
8206
8207 assert_eq!(pipes.selector.name.to_string().as_str(), "Http");
8208 assert_eq!(
8209 pipes.block.content.to_string().as_str(),
8210 format!("-> {}", msg)
8211 );
8212 assert_eq!(
8213 pipes.block.kind,
8214 BlockKind::Terminated(TerminatedBlockKind::Semicolon)
8215 );
8216 assert_eq!(pipes.selector.filters.len(), 0);
8217 assert!(pipes.pipeline_step.is_none());
8218
8219 assert_eq!(
8220 lex_scope_selector(new_span("<Route<Http>>/users/",))
8221 .unwrap()
8222 .0
8223 .len(),
8224 0
8225 );
8226
8227 util::log(result(lex_scope_selector(new_span(
8228 "Route<Http<Get>>/users/",
8229 ))))
8230 .unwrap();
8231
8232 let pipes = util::log(result(lex_scope(new_span(
8233 "Route<Http<Get>>/blah -[Text ]-> {}",
8234 ))))
8235 .unwrap();
8236 assert_eq!(pipes.selector.name.to_string().as_str(), "Route");
8237 assert_eq!(
8238 Some(
8239 pipes
8240 .selector
8241 .children
8242 .as_ref()
8243 .unwrap()
8244 .to_string()
8245 .as_str()
8246 ),
8247 Some("<Http<Get>>")
8248 );
8249 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8250 assert_eq!(pipes.selector.filters.len(), 0);
8251 assert_eq!(
8252 pipes.pipeline_step.as_ref().unwrap().to_string().as_str(),
8253 "-[Text ]->"
8254 );
8255
8256 let pipes = util::log(result(lex_scope(new_span(
8257 "Route<Http<Get>>(auth)/users/ -[Text ]-> {}",
8258 ))))?;
8259 assert_eq!(pipes.selector.name.to_string().as_str(), "Route");
8260 assert_eq!(
8261 Some(
8262 pipes
8263 .selector
8264 .children
8265 .as_ref()
8266 .unwrap()
8267 .to_string()
8268 .as_str()
8269 ),
8270 Some("<Http<Get>>")
8271 );
8272 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8273 assert_eq!(pipes.selector.filters.len(), 1);
8274 assert_eq!(
8275 pipes.pipeline_step.as_ref().unwrap().to_string().as_str(),
8276 "-[Text ]->"
8277 );
8278
8279 let pipes = util::log(result(lex_scope(new_span(
8280 "Route<Http<Get>>(auth)-(blah xyz)/users/ -[Text ]-> {}",
8281 ))))?;
8282 assert_eq!(pipes.selector.name.to_string().as_str(), "Route");
8283 assert_eq!(
8284 Some(
8285 pipes
8286 .selector
8287 .children
8288 .as_ref()
8289 .unwrap()
8290 .to_string()
8291 .as_str()
8292 ),
8293 Some("<Http<Get>>")
8294 );
8295 assert_eq!(pipes.block.kind, BlockKind::Nested(NestedBlockKind::Curly));
8296 assert_eq!(pipes.selector.filters.len(), 2);
8297 assert_eq!(
8298 pipes.pipeline_step.as_ref().unwrap().to_string().as_str(),
8299 "-[Text ]->"
8300 );
8301
8302 let (next, stripped) = strip_comments(new_span(
8303 r#"Route<Http>(auth)-(blah xyz)/users/ -[Text]-> {
8304
8305 Get -> {}
8306 <Put>(superuser) -> localhost:app => &;
8307 Post/users/scott -> localhost:app^Ext<SuperScott> => &;
8308
8309 }"#,
8310 ))?;
8311 let span = span_with_extra(stripped.as_str(), Arc::new(stripped.to_string()));
8312 let pipes = util::log(result(lex_scope(span)))?;
8313
8314 let pipes = util::log(result(lex_scope(new_span("* -> {}"))))?;
8315
8316 Ok(())
8322 }
8323
8324 pub fn test_nesting_bind() {
8325 let pipes = util::log(result(lex_scope(new_span(
8326 r#"
8327
8328
8329 Route<Http>/auth/.*(auth) -> {
8330
8331 <Get>/auth/more ->
8332
8333 }"#,
8334 ))))
8335 .unwrap();
8336 }
8337
8338 pub fn test_root_and_subscope_phases() -> Result<(), SpaceErr> {
8340 let config = r#"
8341Bind(version=1.2.3)-> {
8342 Route -> {
8343 }
8344
8345 Route(auth)-> {
8346 }
8347}
8348
8349 "#;
8350
8351 let root = result(root_scope(new_span(config)))?;
8352
8353 util::log(lex_scopes(root.block.content.clone()));
8354 let sub_scopes = lex_scopes(root.block.content.clone())?;
8355
8356 assert_eq!(sub_scopes.len(), 2);
8357
8358 Ok(())
8359 }
8360 #[test]
8361 pub fn test_variable_name() -> Result<(), SpaceErr> {
8362 assert_eq!(
8363 "v".to_string(),
8364 util::log(result(lowercase1(new_span("v"))))?.to_string()
8365 );
8366 assert_eq!(
8367 "var".to_string(),
8368 util::log(result(skewer_dot(new_span("var"))))?.to_string()
8369 );
8370
8371 util::log(result(variable_name(new_span("var"))))?;
8372 Ok(())
8373 }
8374
8375 pub fn test_subst() -> Result<(), SpaceErr> {
8377 unimplemented!()
8414 }
8415}
8416
8417fn create_command<I: Span>(input: I) -> Res<I, CommandVar> {
8418 tuple((tag("create"), create))(input)
8419 .map(|(next, (_, create))| (next, CommandVar::Create(create)))
8420}
8421
8422pub fn publish_command<I: Span>(input: I) -> Res<I, CommandVar> {
8423 tuple((tag("publish"), space1, publish))(input)
8424 .map(|(next, (_, _, create))| (next, CommandVar::Create(create)))
8425}
8426
8427fn select_command<I: Span>(input: I) -> Res<I, CommandVar> {
8428 tuple((tag("select"), space1, select))(input)
8429 .map(|(next, (_, _, select))| (next, CommandVar::Select(select)))
8430}
8431
8432fn set_command<I: Span>(input: I) -> Res<I, CommandVar> {
8433 tuple((tag("set"), space1, set))(input).map(|(next, (_, _, set))| (next, CommandVar::Set(set)))
8434}
8435
8436fn get_command<I: Span>(input: I) -> Res<I, CommandVar> {
8437 tuple((tag("get"), space1, get))(input).map(|(next, (_, _, get))| (next, CommandVar::Get(get)))
8438}
8439
8440pub fn command_strategy<I: Span>(input: I) -> Res<I, Strategy> {
8441 opt(tuple((tag("?"), multispace0)))(input).map(|(next, hint)| match hint {
8442 None => (next, Strategy::Commit),
8443 Some(_) => (next, Strategy::Ensure),
8444 })
8445}
8446
8447pub fn command<I: Span>(input: I) -> Res<I, CommandVar> {
8448 context(
8449 "command",
8450 alt((
8451 create_command,
8452 publish_command,
8453 select_command,
8454 set_command,
8455 get_command,
8456 fail,
8457 )),
8458 )(input)
8459}
8460
8461pub fn command_line<I: Span>(input: I) -> Res<I, CommandVar> {
8462 tuple((
8463 multispace0,
8464 command,
8465 multispace0,
8466 opt(tag(";")),
8467 multispace0,
8468 ))(input)
8469 .map(|(next, (_, command, _, _, _))| (next, command))
8470}
8471
8472pub fn script_line<I: Span>(input: I) -> Res<I, CommandVar> {
8473 tuple((multispace0, command, multispace0, tag(";"), multispace0))(input)
8474 .map(|(next, (_, command, _, _, _))| (next, command))
8475}
8476
8477pub fn script<I: Span>(input: I) -> Res<I, Vec<CommandVar>> {
8478 many0(script_line)(input)
8479}
8480
8481pub fn consume_command_line<I: Span>(input: I) -> Res<I, CommandVar> {
8482 all_consuming(command_line)(input)
8483}
8484
8485pub fn rec_script_line<I: Span>(input: I) -> Res<I, I> {
8486 recognize(script_line)(input)
8487}
8488
8489
8490
8491pub fn layer<I: Span>(input: I) -> Res<I, Layer> {
8492 let (next, layer) = recognize(camel_case)(input.clone())?;
8493 match Layer::from_str(layer.to_string().as_str()) {
8494 Ok(layer) => Ok((next, layer)),
8495 Err(err) => Err(nom::Err::Error(ErrorTree::from_error_kind(
8496 input,
8497 ErrorKind::Alpha,
8498 ))),
8499 }
8500}
8501
8502fn topic_uuid<I: Span>(input: I) -> Res<I, Topic> {
8503 delimited(tag("Topic<Uuid>("), parse_uuid, tag(")"))(input)
8504 .map(|(next, uuid)| ((next, Topic::Uuid(uuid))))
8505}
8506
8507fn topic_cli<I: Span>(input: I) -> Res<I, Topic> {
8508 value(Topic::Cli, tag("Topic<Cli>"))(input)
8509}
8510
8511fn topic_path<I: Span>(input: I) -> Res<I, Topic> {
8512 delimited(tag("Topic<Path>("), many1(skewer_case), tag(")"))(input)
8513 .map(|(next, segments)| ((next, Topic::Path(segments))))
8514}
8515
8516fn topic_any<I: Span>(input: I) -> Res<I, Topic> {
8517 context("Topic<*>", value(Topic::Any, tag("Topic<*>")))(input)
8518}
8519
8520fn topic_not<I: Span>(input: I) -> Res<I, Topic> {
8521 context("Topic<Not>", value(Topic::Not, tag("Topic<!>")))(input)
8522}
8523
8524pub fn topic_none<I: Span>(input: I) -> Res<I, Topic> {
8525 Ok((input, Topic::None))
8526}
8527
8528pub fn topic<I: Span>(input: I) -> Res<I, Topic> {
8529 context(
8530 "topic",
8531 alt((topic_cli, topic_path, topic_uuid, topic_any, topic_not)),
8532 )(input)
8533}
8534
8535pub fn topic_or_none<I: Span>(input: I) -> Res<I, Topic> {
8536 context("topic_or_none", alt((topic, topic_none)))(input)
8537}
8538
8539pub fn plus_topic_or_none<I: Span>(input: I) -> Res<I, Topic> {
8540 context(
8541 "plus_topic_or_none",
8542 alt((preceded(tag("+"), topic), topic_none)),
8543 )(input)
8544}
8545
8546pub fn port<I: Span>(input: I) -> Res<I, Surface> {
8547 let (next, (point, layer, topic)) = context(
8548 "port",
8549 tuple((
8550 terminated(tw(point_var), tag("@")),
8551 layer,
8552 plus_topic_or_none,
8553 )),
8554 )(input.clone())?;
8555
8556 match point.w.collapse() {
8557 Ok(point) => Ok((next, Surface::new(point, layer, topic))),
8558 Err(err) => {
8559 let err = ErrorTree::from_error_kind(input.clone(), ErrorKind::Alpha);
8560 let loc = input.slice(point.trace.range);
8561 Err(nom::Err::Error(ErrorTree::add_context(
8562 loc,
8563 "resolver-not-available",
8564 err,
8565 )))
8566 }
8567 }
8568}
8569
8570pub type SurfaceSelectorVal = SurfaceSelectorDef<Hop, VarVal<Topic>, VarVal<ValuePattern<Layer>>>;
8571pub type SurfaceSelectorCtx = SurfaceSelectorDef<Hop, Topic, ValuePattern<Layer>>;
8572pub type SurfaceSelector = SurfaceSelectorDef<Hop, Topic, ValuePattern<Layer>>;
8573
8574pub struct SurfaceSelectorDef<Hop, Topic, Layer> {
8575 point: SelectorDef<Hop>,
8576 topic: Topic,
8577 layer: Layer,
8578}
8579
8580pub struct KindLex {
8581 pub base: CamelCase,
8582 pub sub: Option<CamelCase>,
8583 pub specific: Option<Specific>,
8584}
8585
8586impl TryInto<KindParts> for KindLex {
8587 type Error = SpaceErr;
8588
8589 fn try_into(self) -> Result<KindParts, Self::Error> {
8590 Ok(KindParts {
8591 base: BaseKind::try_from(self.base)?,
8592 sub: self.sub,
8593 specific: self.specific,
8594 })
8595 }
8596}
8597
8598pub fn expect<I,O,F>( mut f: F ) -> impl FnMut(I) -> Res<I,O> where F: FnMut(I) -> Res<I,O>+Copy{
8599 move |i: I| {
8600 f(i).map_err( |e| {
8601 match e {
8602 Err::Incomplete(i) => {
8603 Err::Incomplete(i)
8604 }
8605 Err::Error(e) => {
8606 Err::Failure(e)
8607 }
8608 Err::Failure(e) => {
8609 Err::Failure(e)
8610 }
8611 }
8612 })
8613 }
8614}
8615
8616
8617#[cfg(test)]
8618pub mod cmd_test {
8619 use core::str::FromStr;
8620
8621 use nom::error::{VerboseError, VerboseErrorKind};
8622 use nom_supreme::final_parser::{ExtractContext, final_parser};
8623
8624 use cosmic_nom::{new_span, Res};
8625
8626 use crate::command::{Command, CommandVar};
8627 use crate::err::SpaceErr;
8628 use crate::parse::error::result;
8629 use crate::parse::{CamelCase, command, consume_point, create_command, point_selector, publish_command, script, upload_blocks};
8630 use crate::util::ToResolved;
8631 use crate::{BaseKind, KindTemplate, SetProperties};
8632 use crate::kind::Kind;
8633 use crate::point::{PointSeg, RouteSeg};
8634 use crate::selector::{PointHierarchy, PointKindSeg};
8635
8636 pub fn test() -> Result<(), SpaceErr> {
8656 let input = "xreate? localhost<Space>";
8657 match command(new_span(input)) {
8658 Ok(_) => {}
8659 Err(nom::Err::Error(e)) => {
8660 eprintln!("yikes!");
8661 return Err("could not find context".into());
8662 }
8663 Err(e) => {
8664 return Err("some err".into());
8665 }
8666 }
8667 Ok(())
8668 }
8669
8670 #[test]
8671 pub fn test_kind() -> Result<(), SpaceErr> {
8672 let input = "create localhost:users<UserBase<Keycloak>>";
8673 let (_, command) = command(new_span(input))?;
8674 match command {
8675 CommandVar::Create(create) => {
8676 assert_eq!(
8677 create.template.kind.sub,
8678 Some(CamelCase::from_str("Keycloak").unwrap())
8679 );
8680 }
8681 _ => {
8682 panic!("expected create command")
8683 }
8684 }
8685 Ok(())
8686 }
8687
8688 #[test]
8689 pub fn test_script() -> Result<(), SpaceErr> {
8690 let input = r#" create? localhost<Space>;
8691 Xcrete localhost:repo<Base<Repo>>;
8692 create? localhost:repo:tutorial<ArtifactBundleSeries>;
8693 publish? ^[ bundle.zip ]-> localhost:repo:tutorial:1.0.0;
8694 set localhost{ +bind=localhost:repo:tutorial:1.0.0:/bind/localhost.bind } ;
8695 "#;
8696
8697 crate::parse::script(new_span(input))?;
8698 Ok(())
8699 }
8700
8701 #[test]
8702 pub fn test_publish() -> Result<(), SpaceErr> {
8703 let input = r#"publish ^[ bundle.zip ]-> localhost:repo:tutorial:1.0.0"#;
8704 publish_command(new_span(input))?;
8705 Ok(())
8706 }
8707
8708 #[test]
8709 pub fn test_upload_blocks() -> Result<(), SpaceErr> {
8710 let input = r#"publish ^[ bundle.zip ]-> localhost:repo:tutorial:1.0.0"#;
8711 let blocks = result(upload_blocks(new_span(input)))?;
8712 assert_eq!(1, blocks.len());
8713 let block = blocks.get(0).unwrap();
8714 assert_eq!("bundle.zip", block.name.as_str());
8715
8716 let input = r#"publish ^[ ^[ bundle.zip ]-> localhost:repo:tutorial:1.0.0"#;
8718 let blocks = result(upload_blocks(new_span(input)))?;
8719 assert_eq!(0, blocks.len());
8720
8721 let input = r#"publish localhost:repo:tutorial:1.0.0"#;
8723 let blocks = result(upload_blocks(new_span(input)))?;
8724 assert_eq!(0, blocks.len());
8725
8726 Ok(())
8727 }
8728
8729 #[test]
8730 pub fn test_create_kind() -> Result<(), SpaceErr> {
8731 let input = r#"create localhost:repo:tutorial:1.0.0<Repo>"#;
8732 let mut command = result(create_command(new_span(input)))?;
8733 let command = command.collapse()?;
8734 if let Command::Create(create) = command {
8735 let kind = KindTemplate {
8736 base: BaseKind::Repo,
8737 sub: None,
8738 specific: None,
8739 };
8740 assert_eq!(create.template.kind, kind);
8741 } else {
8742 assert!(false);
8743 }
8744
8745 Ok(())
8746 }
8747
8748 #[test]
8749 pub fn test_create_properties() -> Result<(), SpaceErr> {
8750 let input = r#"create localhost:repo:tutorial:1.0.0<Repo>{ +config=the:cool:property }"#;
8751 let mut command = result(create_command(new_span(input)))?;
8752 let command = command.collapse()?;
8753 if let Command::Create(create) = command {
8754 assert!(create.properties.get("config").is_some());
8755 } else {
8756 assert!(false);
8757 }
8758
8759 Ok(())
8760 }
8761
8762 #[test]
8763 pub fn test_selector() {
8764 let less = PointHierarchy::new(RouteSeg::Local, vec![PointKindSeg {
8765 segment: PointSeg::Base("less".to_string()),
8766 kind: Kind::Base
8767 }]
8768 );
8769
8770 let fae = PointHierarchy::new(RouteSeg::Local, vec![PointKindSeg {
8771 segment: PointSeg::Base("fae".to_string()),
8772 kind: Kind::Base
8773 },
8774 PointKindSeg {
8775 segment: PointSeg::Base("dra".to_string()),
8776 kind: Kind::User
8777 }]
8778 );
8779
8780
8781 assert!(result(point_selector(new_span("less"))).unwrap().matches(&less));
8782 assert!(result(point_selector(new_span("*"))).unwrap().matches(&less));
8783 assert!(!result(point_selector(new_span("*"))).unwrap().matches(&fae ));
8784 assert!(result(point_selector(new_span("*:dra"))).unwrap().matches(&fae ));
8785 assert!(!result(point_selector(new_span("*:dra"))).unwrap().matches(&less ));
8786 assert!(result(point_selector(new_span("fae:*"))).unwrap().matches(&fae));
8787 assert!(result(point_selector(new_span("**<User>"))).unwrap().matches(&fae));
8788 assert!(!result(point_selector(new_span("**<User>"))).unwrap().matches(&less));
8789 assert!(result(point_selector(new_span("**"))).unwrap().matches(&less));
8790 assert!(result(point_selector(new_span("**"))).unwrap().matches(&fae));
8791 assert!(!result(point_selector(new_span("**<Base>"))).unwrap().matches(&fae));
8792
8793 let less = result(point_selector(new_span("less"))).unwrap();
8794 }
8795}