1- use crate :: { yacc:: ParserError , Location , Span } ;
1+ use crate :: {
2+ markmap:: MarkMap ,
3+ yacc:: { ParserError , YaccKind , YaccOriginalActionKind } ,
4+ Location , Span ,
5+ } ;
26use lazy_static:: lazy_static;
37use regex:: { Regex , RegexBuilder } ;
48use std:: collections:: { hash_map:: Entry , HashMap } ;
59use std:: { error:: Error , fmt} ;
610
11+ /// An error regarding the `%grmtools` header section.
12+ ///
13+ /// It could be any of:
14+ ///
15+ /// * An error during parsing the section.
16+ /// * An error resulting from a value in the section having an invalid value.
717#[ derive( Debug , Clone ) ]
818pub struct HeaderError {
919 pub kind : HeaderErrorKind ,
@@ -32,6 +42,7 @@ pub enum HeaderErrorKind {
3242 ExpectedToken ( char ) ,
3343 DuplicateEntry ,
3444 InvalidEntry ( & ' static str ) ,
45+ ConversionError ( & ' static str , & ' static str ) ,
3546}
3647
3748impl fmt:: Display for HeaderErrorKind {
@@ -42,6 +53,9 @@ impl fmt::Display for HeaderErrorKind {
4253 HeaderErrorKind :: ExpectedToken ( c) => & format ! ( "Expected token: '{}" , c) ,
4354 HeaderErrorKind :: InvalidEntry ( s) => & format ! ( "Invalid entry: '{}'" , s) ,
4455 HeaderErrorKind :: DuplicateEntry => "Duplicate Entry" ,
56+ HeaderErrorKind :: ConversionError ( t, err_str) => {
57+ & format ! ( "Converting header value to type '{}': {}" , t, err_str)
58+ }
4559 } ;
4660 write ! ( f, "{}" , s)
4761 }
@@ -64,6 +78,7 @@ impl fmt::Display for HeaderErrorKind {
6478/// }
6579/// ```
6680#[ derive( Debug , Eq , PartialEq ) ]
81+ #[ doc( hidden) ]
6782pub struct Namespaced {
6883 pub namespace : Option < ( String , Location ) > ,
6984 pub member : ( String , Location ) ,
@@ -91,7 +106,12 @@ pub struct GrmtoolsSectionParser<'input> {
91106 required : bool ,
92107}
93108
109+ /// The value contained within a `Header`
110+ ///
111+ /// To be useful across diverse crates this types fields are limited to types derived from `core::` types.
112+ /// like booleans, numeric types, and string values.
94113#[ derive( Debug , Eq , PartialEq ) ]
114+ #[ doc( hidden) ]
95115pub enum Value {
96116 Flag ( bool , Location ) ,
97117 Setting ( Setting ) ,
@@ -345,6 +365,155 @@ impl<'input> GrmtoolsSectionParser<'input> {
345365 }
346366}
347367
368+ /// A data structure representation of the %grmtools section.
369+ pub type Header = MarkMap < String , ( Location , Value ) > ;
370+
371+ impl TryFrom < YaccKind > for Value {
372+ type Error = HeaderError ;
373+ fn try_from ( kind : YaccKind ) -> Result < Value , HeaderError > {
374+ let from_loc = Location :: Other ( "From<YaccKind>" . to_string ( ) ) ;
375+ Ok ( match kind {
376+ YaccKind :: Grmtools => Value :: Setting ( Setting :: Unitary ( Namespaced {
377+ namespace : Some ( ( "yacckind" . to_string ( ) , from_loc. clone ( ) ) ) ,
378+ member : ( "grmtools" . to_string ( ) , from_loc) ,
379+ } ) ) ,
380+ YaccKind :: Eco => Value :: Setting ( Setting :: Unitary ( Namespaced {
381+ namespace : Some ( ( "yacckind" . to_string ( ) , from_loc. clone ( ) ) ) ,
382+ member : ( "eco" . to_string ( ) , from_loc) ,
383+ } ) ) ,
384+ YaccKind :: Original ( action_kind) => Value :: Setting ( Setting :: Constructor {
385+ ctor : Namespaced {
386+ namespace : Some ( ( "yacckind" . to_string ( ) , from_loc. clone ( ) ) ) ,
387+ member : ( "original" . to_string ( ) , from_loc. clone ( ) ) ,
388+ } ,
389+ arg : match action_kind {
390+ YaccOriginalActionKind :: NoAction => Namespaced {
391+ namespace : Some ( ( "yaccoriginalactionkind" . to_string ( ) , from_loc. clone ( ) ) ) ,
392+ member : ( "noaction" . to_string ( ) , from_loc) ,
393+ } ,
394+ YaccOriginalActionKind :: UserAction => Namespaced {
395+ namespace : Some ( ( "yaccoriginalactionkind" . to_string ( ) , from_loc. clone ( ) ) ) ,
396+ member : ( "useraction" . to_string ( ) , from_loc) ,
397+ } ,
398+ YaccOriginalActionKind :: GenericParseTree => Namespaced {
399+ namespace : Some ( ( "yaccoriginalactionkind" . to_string ( ) , from_loc. clone ( ) ) ) ,
400+ member : ( "genericparsetree" . to_string ( ) , from_loc) ,
401+ } ,
402+ } ,
403+ } ) ,
404+ } )
405+ }
406+ }
407+
408+ impl TryFrom < & Value > for YaccKind {
409+ type Error = HeaderError ;
410+ fn try_from ( value : & Value ) -> Result < YaccKind , HeaderError > {
411+ let mut err_locs = Vec :: new ( ) ;
412+ match value {
413+ Value :: Flag ( _, loc) => Err ( HeaderError {
414+ kind : HeaderErrorKind :: ConversionError (
415+ "From<YaccKind>" ,
416+ "Cannot convert boolean to YaccKind" ,
417+ ) ,
418+ locations : vec ! [ loc. clone( ) ] ,
419+ } ) ,
420+ Value :: Setting ( Setting :: Num ( _, loc) ) => Err ( HeaderError {
421+ kind : HeaderErrorKind :: ConversionError (
422+ "From<YaccKind>" ,
423+ "Cannot convert number to YaccKind" ,
424+ ) ,
425+ locations : vec ! [ loc. clone( ) ] ,
426+ } ) ,
427+ Value :: Setting ( Setting :: Unitary ( Namespaced {
428+ namespace,
429+ member : ( yk_value, yk_value_loc) ,
430+ } ) ) => {
431+ if let Some ( ( ns, ns_loc) ) = namespace {
432+ if ns != "yacckind" {
433+ err_locs. push ( ns_loc. clone ( ) ) ;
434+ }
435+ }
436+ let yacckinds = [
437+ ( "grmtools" . to_string ( ) , YaccKind :: Grmtools ) ,
438+ ( "eco" . to_string ( ) , YaccKind :: Eco ) ,
439+ ] ;
440+ let yk_found = yacckinds
441+ . iter ( )
442+ . find_map ( |( yk_str, yk) | ( yk_str == yk_value) . then_some ( yk) ) ;
443+ if let Some ( yk) = yk_found {
444+ if err_locs. is_empty ( ) {
445+ Ok ( * yk)
446+ } else {
447+ Err ( HeaderError {
448+ kind : HeaderErrorKind :: InvalidEntry ( "yacckind" ) ,
449+ locations : err_locs,
450+ } )
451+ }
452+ } else {
453+ err_locs. push ( yk_value_loc. clone ( ) ) ;
454+ Err ( HeaderError {
455+ kind : HeaderErrorKind :: InvalidEntry ( "yacckind" ) ,
456+ locations : err_locs,
457+ } )
458+ }
459+ }
460+ Value :: Setting ( Setting :: Constructor {
461+ ctor :
462+ Namespaced {
463+ namespace : yk_namespace,
464+ member : ( yk_str, yk_loc) ,
465+ } ,
466+ arg :
467+ Namespaced {
468+ namespace : ak_namespace,
469+ member : ( ak_str, ak_loc) ,
470+ } ,
471+ } ) => {
472+ if let Some ( ( yk_ns, yk_ns_loc) ) = yk_namespace {
473+ if yk_ns != "yacckind" {
474+ err_locs. push ( yk_ns_loc. clone ( ) ) ;
475+ }
476+ }
477+
478+ if yk_str != "original" {
479+ err_locs. push ( yk_loc. clone ( ) ) ;
480+ }
481+
482+ if let Some ( ( ak_ns, ak_ns_loc) ) = ak_namespace {
483+ if ak_ns != "yaccoriginalactionkind" {
484+ err_locs. push ( ak_ns_loc. clone ( ) ) ;
485+ }
486+ }
487+ let actionkinds = [
488+ ( "noaction" , YaccOriginalActionKind :: NoAction ) ,
489+ ( "useraction" , YaccOriginalActionKind :: UserAction ) ,
490+ ( "genericparsetree" , YaccOriginalActionKind :: GenericParseTree ) ,
491+ ] ;
492+ let yk_found = actionkinds. iter ( ) . find_map ( |( actionkind_str, actionkind) | {
493+ ( ak_str == actionkind_str) . then_some ( YaccKind :: Original ( * actionkind) )
494+ } ) ;
495+
496+ if let Some ( yk) = yk_found {
497+ if err_locs. is_empty ( ) {
498+ Ok ( yk)
499+ } else {
500+ Err ( HeaderError {
501+ kind : HeaderErrorKind :: InvalidEntry ( "yacckind" ) ,
502+ locations : err_locs,
503+ } )
504+ }
505+ } else {
506+ err_locs. push ( ak_loc. clone ( ) ) ;
507+ Err ( HeaderError {
508+ kind : HeaderErrorKind :: InvalidEntry ( "yacckind" ) ,
509+ locations : err_locs,
510+ } )
511+ }
512+ }
513+ }
514+ }
515+ }
516+
348517#[ cfg( test) ]
349518mod test {
350519 use super :: * ;
0 commit comments