{- Copyright (C) 2009 Andrejs Sisojevs All rights reserved. For license and copyright information, see the file COPYRIGHT -} -------------------------------------------------------------------------- -------------------------------------------------------------------------- -- | Here are declared 'LocalizableTemplate' (also called PCLT) -- and 'LocalizedTemplate'. -- Here by localization is meant localization in languages. -- First (localizable template) is above languages, -- while second (localized template) is a template version -- in a concrete language. module Text.PCLT.Template where import qualified Data.ByteString.Lazy.UTF8.Unified as Lazy (ByteString) import qualified Data.ByteString.Lazy.UTF8.Unified as B hiding (ByteString) import Data.List import qualified Data.Map as M import Data.Map (Map, (!)) import Data.MyHelpers import Data.Typeable import Text.PCLT.Parser.AdvancedSepBy import Text.PCLT.Parser.ParserInternals import Text.PCLT.CommonTypes import Text.PCLT.Config import Text.PCLT.SDL -- * Template pieces -- | These are types of template pieces. They are made by 'ssm2ldtm' -- from 'Text.PCLT.Parser.AdvancedSepBy.SeparatedSectorMarker' data PCS_SpecificMarkings = PlainText_LngTplM | Parameter_LngTplM | Composite_LngTplM | Unsupported_LngTplM SeparatedSectorMarker deriving (Eq, Show, Typeable) ssm2ldtm :: SeparatedSectorMarker -> PCS_SpecificMarkings ssm2ldtm ssm = case ssm of Error_SSM err_msg -> Unsupported_LngTplM ssm InnerMarker_SSM i -> if i == 0 then PlainText_LngTplM else if i == 1 then Parameter_LngTplM else if i == 2 then Composite_LngTplM else Unsupported_LngTplM ssm _ -> Unsupported_LngTplM ssm -- | Template content. type LngTpl_AbstractedString = [(PCS_SpecificMarkings, Lazy.ByteString, MarkedChunkLength)] -- | Extract a list of parameter names from a template content. listOfParams :: LngTpl_AbstractedString -> [ParamName_LBS] listOfParams str_struct = foldl (\ accum (marker, str, _) -> case marker == Parameter_LngTplM of {True -> str : accum; False -> accum }) [] str_struct ------------------------------------------------------------------------ -- * Parsing from a lazy ByteString to a localized template content type ParserBadResult = String -- | These errors are possible only if program is wrong. data PCLT_ParserLowLevelFailure = UnexpectedParserResult_PLLF_PCLT ParserBadResult | BadMarker_PLLF_PCLT SeparatedSectorMarker Lazy.ByteString ChunkIndexInList_ deriving (Show, Typeable) -- | The parsing uses parameters -- 'Test.PCLT.Config.pcsParameterPlaceholderWrapper' and -- 'Test.PCLT.Config.pcsCompositePlaceholderWrapper' of -- 'Test.PCLT.Config.PCLT_InnerConfig'. -- The list @[PCLT_CompositeKey]@ in the result is a list of composite keys -- (template IDs, used by template as inclusions) doTheParse :: PCLT_InnerConfig -> Lazy.ByteString -> ( [PCLT_ParserLowLevelFailure], Maybe ( LngTpl_AbstractedString, [PCLT_CompositeKey] )) doTheParse pcsc_config str = let parser = sepBySome anyChar standardMarkingStrategy [ stringLBS $ pcsParameterPlaceholderWrapper pcsc_config , stringLBS $ pcsCompositePlaceholderWrapper pcsc_config ] in case parse parser str of ( IllegalInput , _ ) -> ([UnexpectedParserResult_PLLF_PCLT "IllegalInput"], Nothing) ( ReachedEOF , _ ) -> ([UnexpectedParserResult_PLLF_PCLT "ReachedEOF"] , Nothing) ( Success marked_chunks_list, _ ) -> let _fixed_marked_chunks_list = standardMarkingStrategyFix_StripEmptyChunks marked_chunks_list list_of_parser_errors = map (\ (ssm, s, idx) -> BadMarker_PLLF_PCLT ssm s idx) $ retrieveErrorsMarkingsList _fixed_marked_chunks_list non_plain_markings_map = retrieveNonPlainMarkingsMap _fixed_marked_chunks_list fixed_marked_chunks_list = map (\ (ssm, str, len) -> (ssm2ldtm ssm, str, len)) _fixed_marked_chunks_list list_of_composites_keys = map B.unpack $ fst $ unzip $ getListOfMarkings non_plain_markings_map 2 in (list_of_parser_errors, Just (fixed_marked_chunks_list, list_of_composites_keys)) ------------------------------------------------------------------------ -- * Localized template type PCLT_CatalogMap = Map PCLT_ID LocalizableTemplate type LngTpl_SubCompositesMap = PCLT_CatalogMap data LocalizedTemplate = LocalizedTemplate { ldtAbstractedString :: LngTpl_AbstractedString -- | Each composition tree is kept together with each -- localization. This is done for speedup and is a source -- of complexities, when forming a catalog and sustaining it's -- data consistency. So it comes to this: -- templates are purely-referenced by -- -- * catalog ('PCLT_CatalogMap') and -- -- * templates, that uses them as composites -- ('LngTpl_SubCompositesMap'). -- -- By \"purely-reference\" here is meant, that templates are -- formed only once, they have one instace in memory, but -- are referenced twice - from composeds and from catalog map , ldtSubcompositesMap :: LngTpl_SubCompositesMap } deriving (Show, Typeable) -- * Text.PCLT.Config.pcsStrictOrient_ofParamsAndCmpsts_onDfltLngTplsSets type DefaultLngTpl = LocalizedTemplate type NondefaultLngTpl = LocalizedTemplate -- | Carrying strict orientation routines. See description of -- 'Text.PCLT.Config.StrictOrient_ofParamsAndCmpsts_onDfltLngTplsSets'. compareStrictOrientationOnDefault :: PCLT_ID -> StrictOrient_ofParamsAndCmpsts_onDfltLngTplsSets -> NondefaultLngTpl -> DefaultLngTpl -> Bool compareStrictOrientationOnDefault tpl_id so nondflt_ldt dflt_ldt = let ( dflt_subcomps , dflt_params ) = (fst . unzip . M.toList . ldtSubcompositesMap, listOfParams . ldtAbstractedString) `apFrom2ple` dflt_ldt (nondflt_subcomps , nondflt_params ) = (fst . unzip . M.toList . ldtSubcompositesMap, listOfParams . ldtAbstractedString) `apFrom2ple` nondflt_ldt in _compareStrictOrientationOnDefault tpl_id so (nondflt_subcomps, nondflt_params) (dflt_subcomps, dflt_params) _compareStrictOrientationOnDefault :: PCLT_ID -> StrictOrient_ofParamsAndCmpsts_onDfltLngTplsSets -> ([PCLT_ID], [ParamName_LBS]) -> ([PCLT_ID], [ParamName_LBS]) -> Bool _compareStrictOrientationOnDefault tpl_id so (nondflt_subcomps, nondflt_params) (dflt_subcomps, dflt_params) = let memb = elem tpl_id $ soExcludingInComposites so crit1 = soStrict_IsIt so && (not memb) crit2 = (not $ soStrict_IsIt so) && memb crit = crit1 || crit2 local_c_exclusions = soExcludingComposites so ++ (snd $ unzip $ filter (\ (_tpl_id, _) -> _tpl_id == tpl_id) (soExcludingCompComposites so) ) local_p_exclusions = map B.pack ( soExcludingParameters so ++ (snd $ unzip $ filter (\ (_tpl_id, _) -> _tpl_id == tpl_id) (soExcludingCompParameters so) ) ) op :: Eq a => [a] -> [a] -> [a] op = case crit of True -> (\\) False -> intersect ( so_dflt_subcomps , so_dflt_params ) = ( dflt_subcomps `op` local_c_exclusions, dflt_params `op` local_p_exclusions) (so_nondflt_subcomps , so_nondflt_params ) = ( nondflt_subcomps `op` local_c_exclusions, nondflt_params `op` local_p_exclusions) ( so_union_subcomps , so_union_params ) = ( so_dflt_subcomps `union` so_nondflt_subcomps, so_dflt_params `union` so_nondflt_params) (so_nondflt_subcomps_len, so_nondflt_params_len) = (length so_nondflt_subcomps, length so_nondflt_params) ( so_dflt_subcomps_len, so_dflt_params_len) = (length so_dflt_subcomps, length so_dflt_params) ( so_union_subcomps_len, so_union_params_len) = (length so_union_subcomps, length so_union_params) in so_union_subcomps_len == so_dflt_subcomps_len && so_union_params_len == so_dflt_params_len && so_union_subcomps_len == so_nondflt_subcomps_len && so_union_params_len == so_nondflt_params_len ------------------------------------------------------------------------ -- * Requirement for making a representation from template - SDL -- | This is an extending wrapper around SDL. It is used for specification -- of requirement for making representation from template. This specification -- is attached to every localizable template in PCLT catalog data PCLT_ShowDetalizationLevel = -- | Plain SDL, nominal. If SDL of representation reciever -- is less then that, then template cann't be used in representation -- generation. PCLT_SDL ShowDetalizationLevel -- | \"The requirement is the same as is specified -- for referenced template\". | PCLT_SDL_ToTemplateLink PCLT_ID -- | \"The requirement is the same as is specified a for referenced -- template, which is referenced by a @PCSI_PV@ value of referenced -- parameter (of current template)\". | PCLT_SDL_ToParamCompositeLink PCLT_ParamKey -- | In input data for catalog formation the given specification -- is errornous. -- If config's ("Text.PCLT.Config") parameters -- 'Text.PCLT.Config.pcsAllowEmptySDL_parseItByModusMargin' and/or -- 'Text.PCLT.Config.pcsAllowUnreadableSDL_parseIdByModusMargin' are -- positive, then instead of @PCLT_SDL_Errornous@ the parser -- ('str2PCLT_SDL') will use 'Text.PCLT.SDL.marginOfSDLModus' to set -- valid specification. When representation generator meets -- @PCLT_SDL_Errornous@ it won't use template, and return an error. | PCLT_SDL_Errornous PCLT_ErrornousSDL deriving (Eq, Show, Typeable) type PCLT_RequiredShowDetalizationLevel = PCLT_ShowDetalizationLevel type PCLT_AllocatedShowDetalizationLevel = PCLT_ShowDetalizationLevel -- | Raw templates (both localizeds, and localizables). -- Input data for catalog formation. Used by @HasStaticRawPCLTs@ class -- (declared in "Text.PCLT.HasStaticRawPCLTs") data PCLT_RawCatalogData = PCLT_RawCatalogData (Map PCLT_ID (Map LanguageName Lazy.ByteString, PCLT_RequiredShowDetalizationLevel)) deriving (Show, Typeable) -- | This is a bad result of parsing some 'String' -- into 'PCLT_ShowDetalizationLevel'. The second argument is this bad input. data PCLT_ErrornousSDL = UnreadableSDL_ESDL SDLModus String deriving (Eq, Show, Typeable) -- | A constant currently set to 25. It is used in a parser 'str2PCLT_SDL': -- if the input is errornous, this much symbols of input are saved -- in 'UnreadableSDL_ESDL'. If input is bigger, then the saved trunc is -- tailed with \"...\" __const_esdl_rawinputshowsize_inShowAsPCSI :: Int __const_esdl_rawinputshowsize_inShowAsPCSI = 25 -- | Parse 'String' into 'PCLT_ShowDetalizationLevel'. First of all parser -- tries 'Text.PCLT.SDL.strict_str2sdl'. Then, if failed, parser uses following -- config entries: -- -- * 'Text.PCLT.Config.pcsParameterPlaceholderWrapper' - -- if prefix and postfix of input is this (by default it is \"\@\@\|\"), -- then it is parsed into 'PCLT_SDL_ToParamCompositeLink' -- -- * 'Text.PCLT.Config.pcsCompositePlaceholderWrapper' - -- if prefix and postfix of input is this (by default it is \"\#\#\|\"), -- then it is parsed into 'PCLT_SDL_ToTemplateLink' -- -- * 'Text.PCLT.Config.pcsAllowEmptySDL_parseItByModusMargin' - -- if it is positive and input is empty, then it gets parsed into -- (@PCLT_SDL $ 'Text.PCLT.SDL.marginOfSDLModus' modus@), where modus -- is first argument; esle, if parameter is negative and input is empty, -- it is parsed to 'PCLT_SDL_Errornous' -- -- * 'Text.PCLT.Config.pcsAllowUnreadableSDL_parseIdByModusMargin' - -- if it is positive and input is unparsable, then it gets parsed into -- @'PCLT_SDL' $ 'Text.PCLT.SDL.marginOfSDLModus' modus@, where modus -- is first argument; esle, if parameter is negative and input is unparsable, -- it is parsed to 'PCLT_SDL_Errornous' str2PCLT_SDL :: SDLModus -> String -> PCLT_InnerConfig -> PCLT_ShowDetalizationLevel str2PCLT_SDL sdlm s cfg = let cmpst_phw_str = B.unpack $ pcsCompositePlaceholderWrapper cfg param_phw_str = B.unpack $ pcsParameterPlaceholderWrapper cfg stripOfWrapper subj0 wrp = let wrp_len = length wrp subj1 = drop wrp_len subj0 subj1_len = length subj1 in take (subj1_len - wrp_len) subj1 in case strict_str2sdl s of Just n -> PCLT_SDL n Nothing -> case isPrefixOf cmpst_phw_str s && isSuffixOf cmpst_phw_str s of True -> PCLT_SDL_ToTemplateLink (stripOfWrapper s cmpst_phw_str) False -> case isPrefixOf param_phw_str s && isSuffixOf param_phw_str s of True -> PCLT_SDL_ToParamCompositeLink (stripOfWrapper s param_phw_str) False -> let cond1 = pcsAllowEmptySDL_parseItByModusMargin cfg && null s cond2 = pcsAllowUnreadableSDL_parseIdByModusMargin cfg cond = cond1 || cond2 in case cond of True -> PCLT_SDL $ marginOfSDLModus sdlm False -> PCLT_SDL_Errornous $ UnreadableSDL_ESDL sdlm $ truncLiterary s __const_esdl_rawinputshowsize_inShowAsPCSI --------------------------------------------------------------------------------- -- * Localizable template data LocalizableTemplate = LocalizableTemplate { pcltLocalizationsMap :: Map LanguageName LocalizedTemplate -- | If SDL of representation reciever -- is less then that, then template cann't be used in representation -- generation. , pcltRequiredSDL :: PCLT_RequiredShowDetalizationLevel } deriving (Show, Typeable)