gedcom 0.1.0.0 → 0.2.0.0
raw patch · 14 files changed
+1718/−1541 lines, 14 filesdep +hspecdep ~basedep ~megaparsecdep ~monad-loopsPVP ok
version bump matches the API change (PVP)
Dependencies added: hspec
Dependency ranges changed: base, megaparsec, monad-loops, time
API changes (from Hackage documentation)
- Data.Gedcom: AFN :: Text -> AFN
- Data.Gedcom: AKA :: NameType
- Data.Gedcom: Address :: Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> ContactDetails -> Address
- Data.Gedcom: Adopted :: Pedigree
- Data.Gedcom: Adoption :: (Maybe AdoptionDetail) -> IndividualEventType
- Data.Gedcom: AdoptionDetail :: (GDRef Family) -> (Maybe Parent) -> AdoptionDetail
- Data.Gedcom: Annuled :: FamilyEventType
- Data.Gedcom: Association :: GDRef Individual -> Text -> [SourceCitation] -> [GDRef Note] -> Association
- Data.Gedcom: Baptism :: IndividualEventType
- Data.Gedcom: BarMitzvah :: IndividualEventType
- Data.Gedcom: BasMitzvah :: IndividualEventType
- Data.Gedcom: Birth :: (Maybe (GDRef Family)) -> IndividualEventType
- Data.Gedcom: BirthName :: NameType
- Data.Gedcom: Blessing :: IndividualEventType
- Data.Gedcom: BothParents :: Parent
- Data.Gedcom: Burial :: IndividualEventType
- Data.Gedcom: ByBirth :: Pedigree
- Data.Gedcom: CallNumber :: Text -> (Maybe MultimediaType) -> CallNumber
- Data.Gedcom: Caste :: Text -> IndividualAttributeType
- Data.Gedcom: Census :: EventType
- Data.Gedcom: Challenged :: ChildLinkStatus
- Data.Gedcom: ChangeDate :: UTCTime -> (Maybe (GDRef Note)) -> ChangeDate
- Data.Gedcom: Charset :: Text -> (Maybe Text) -> Charset
- Data.Gedcom: ChildToFamilyLink :: GDRef Family -> Maybe Pedigree -> Maybe ChildLinkStatus -> [GDRef Note] -> ChildToFamilyLink
- Data.Gedcom: Christening :: (Maybe (GDRef Family)) -> IndividualEventType
- Data.Gedcom: ChristeningAdult :: IndividualEventType
- Data.Gedcom: Confidential :: RestrictionNotice
- Data.Gedcom: Confirmation :: IndividualEventType
- Data.Gedcom: ContactDetails :: [Text] -> [Text] -> [Text] -> [Text] -> ContactDetails
- Data.Gedcom: Corp :: Text -> Maybe Address -> Corp
- Data.Gedcom: Cremation :: IndividualEventType
- Data.Gedcom: Date :: Calendar -> (Maybe Word) -> (Maybe Word) -> Year -> Date
- Data.Gedcom: DateAbout :: Date -> DateApprox
- Data.Gedcom: DateAfter :: Date -> DateRange
- Data.Gedcom: DateApproxV :: DateApprox -> DateValue
- Data.Gedcom: DateBefore :: Date -> DateRange
- Data.Gedcom: DateBetween :: Date -> Date -> DateRange
- Data.Gedcom: DateCalculated :: Date -> DateApprox
- Data.Gedcom: DateEstimated :: Date -> DateApprox
- Data.Gedcom: DateFrom :: Date -> (Maybe Date) -> DatePeriod
- Data.Gedcom: DatePeriodV :: DatePeriod -> DateValue
- Data.Gedcom: DatePhrase :: (Maybe Date) -> Text -> DateValue
- Data.Gedcom: DateRangeV :: DateRange -> DateValue
- Data.Gedcom: DateTo :: Date -> DatePeriod
- Data.Gedcom: DateV :: Date -> DateValue
- Data.Gedcom: Death :: IndividualEventType
- Data.Gedcom: Disproved :: ChildLinkStatus
- Data.Gedcom: Divorce :: FamilyEventType
- Data.Gedcom: DivorceFiled :: FamilyEventType
- Data.Gedcom: Education :: Text -> IndividualAttributeType
- Data.Gedcom: Emigration :: IndividualEventType
- Data.Gedcom: Engagement :: FamilyEventType
- Data.Gedcom: EventDetail :: Maybe Text -> Maybe DateValue -> Maybe Place -> Maybe Address -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe RestrictionNotice -> [GDRef Note] -> [SourceCitation] -> [GDRef Multimedia] -> EventDetail
- Data.Gedcom: EventType :: Text -> EventType
- Data.Gedcom: Fact :: Text -> IndividualAttributeType
- Data.Gedcom: FamCensus :: FamilyEventType
- Data.Gedcom: Family :: Maybe RestrictionNotice -> [FamilyEvent] -> Maybe (GDRef Individual) -> Maybe (GDRef Individual) -> [GDRef Individual] -> Maybe Word -> [GDRef Submitter] -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> [GDRef Note] -> [SourceCitation] -> [GDRef Multimedia] -> Family
- Data.Gedcom: FamilyEvent :: FamilyEventType -> FamilyEventDetail -> FamilyEvent
- Data.Gedcom: FamilyEventDetail :: Maybe Word -> Maybe Word -> EventDetail -> FamilyEventDetail
- Data.Gedcom: FamilyEventType :: Text -> FamilyEventType
- Data.Gedcom: FamilyEventTypeV :: FamilyEventType -> EventType
- Data.Gedcom: Female :: Sex
- Data.Gedcom: FirstCommunion :: IndividualEventType
- Data.Gedcom: Foster :: Pedigree
- Data.Gedcom: French :: Calendar
- Data.Gedcom: Gedcom :: Header -> [GDRef Family] -> [GDRef Individual] -> [GDRef Multimedia] -> [GDRef Note] -> [GDRef Repository] -> [GDRef Source] -> [GDRef Submitter] -> Gedcom
- Data.Gedcom: GedcomFormat :: Text -> GedcomForm -> GedcomFormat
- Data.Gedcom: GedcomLineageLinked :: GedcomForm
- Data.Gedcom: GedcomUnsupported :: Text -> GedcomForm
- Data.Gedcom: Graduation :: IndividualEventType
- Data.Gedcom: Gregorian :: Calendar
- Data.Gedcom: Hangul :: PhoneticType
- Data.Gedcom: Header :: HeaderSource -> Maybe Text -> Maybe UTCTime -> GDRef Submitter -> Maybe (GDRef Submission) -> Maybe FilePath -> Maybe Text -> GedcomFormat -> Charset -> Maybe Language -> Maybe [Text] -> Maybe Text -> Header
- Data.Gedcom: HeaderSource :: Text -> Maybe Text -> Maybe Text -> Maybe Corp -> Maybe HeaderSourceData -> HeaderSource
- Data.Gedcom: HeaderSourceData :: Text -> Maybe UTCTime -> Maybe Text -> HeaderSourceData
- Data.Gedcom: Hebrew :: Calendar
- Data.Gedcom: Husband :: Parent
- Data.Gedcom: Immigrant :: NameType
- Data.Gedcom: Immigration :: IndividualEventType
- Data.Gedcom: Individual :: Maybe RestrictionNotice -> Maybe PersonalName -> Maybe Sex -> [IndividualEvent] -> [IndividualAttribute] -> [ChildToFamilyLink] -> [SpouseToFamilyLink] -> [GDRef Submitter] -> [Association] -> [GDRef Individual] -> [GDRef Submitter] -> [GDRef Submitter] -> Maybe RFN -> Maybe AFN -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> [GDRef Note] -> [SourceCitation] -> [GDRef Multimedia] -> Individual
- Data.Gedcom: IndividualAttribute :: IndividualAttributeType -> (IndividualEventDetail) -> IndividualAttribute
- Data.Gedcom: IndividualEvent :: IndividualEventType -> IndividualEventDetail -> IndividualEvent
- Data.Gedcom: IndividualEventDetail :: EventDetail -> Maybe Word -> IndividualEventDetail
- Data.Gedcom: IndividualEventType :: Text -> IndividualEventType
- Data.Gedcom: IndividualEventTypeV :: IndividualEventType -> EventType
- Data.Gedcom: IndvCensus :: IndividualEventType
- Data.Gedcom: Julian :: Calendar
- Data.Gedcom: Kana :: PhoneticType
- Data.Gedcom: Language :: Text -> Language
- Data.Gedcom: Latitude :: Double -> Latitude
- Data.Gedcom: Locked :: RestrictionNotice
- Data.Gedcom: Longitude :: Double -> Longitude
- Data.Gedcom: MF_BMP :: MultimediaFileFormat
- Data.Gedcom: MF_GIF :: MultimediaFileFormat
- Data.Gedcom: MF_JPG :: MultimediaFileFormat
- Data.Gedcom: MF_OLE :: MultimediaFileFormat
- Data.Gedcom: MF_OTHER :: Text -> MultimediaFileFormat
- Data.Gedcom: MF_PCX :: MultimediaFileFormat
- Data.Gedcom: MF_TIF :: MultimediaFileFormat
- Data.Gedcom: MF_WAV :: MultimediaFileFormat
- Data.Gedcom: MT_AUDIO :: MultimediaType
- Data.Gedcom: MT_BOOK :: MultimediaType
- Data.Gedcom: MT_CARD :: MultimediaType
- Data.Gedcom: MT_ELECTRONIC :: MultimediaType
- Data.Gedcom: MT_FICHE :: MultimediaType
- Data.Gedcom: MT_FILM :: MultimediaType
- Data.Gedcom: MT_MAGAZINE :: MultimediaType
- Data.Gedcom: MT_MANUSCRIPT :: MultimediaType
- Data.Gedcom: MT_MAP :: MultimediaType
- Data.Gedcom: MT_NEWSPAPER :: MultimediaType
- Data.Gedcom: MT_OTHER :: Text -> MultimediaType
- Data.Gedcom: MT_PHOTO :: MultimediaType
- Data.Gedcom: MT_TOMBSTONE :: MultimediaType
- Data.Gedcom: MT_VIDEO :: MultimediaType
- Data.Gedcom: Maiden :: NameType
- Data.Gedcom: Male :: Sex
- Data.Gedcom: MapCoord :: Longitude -> Latitude -> MapCoord
- Data.Gedcom: Marriage :: FamilyEventType
- Data.Gedcom: MarriageBann :: FamilyEventType
- Data.Gedcom: MarriageContract :: FamilyEventType
- Data.Gedcom: MarriageLicense :: FamilyEventType
- Data.Gedcom: MarriageSettlement :: FamilyEventType
- Data.Gedcom: Married :: NameType
- Data.Gedcom: Multimedia :: [MultimediaFile] -> Maybe Text -> [UserReference] -> Maybe RIN -> [GDRef Note] -> [SourceCitation] -> Maybe ChangeDate -> Multimedia
- Data.Gedcom: MultimediaFile :: Text -> MultimediaFormat -> Maybe Text -> MultimediaFile
- Data.Gedcom: MultimediaFormat :: MultimediaFileFormat -> (Maybe MultimediaType) -> MultimediaFormat
- Data.Gedcom: NChildren :: Word -> IndividualAttributeType
- Data.Gedcom: NMarriages :: Word -> IndividualAttributeType
- Data.Gedcom: Name :: Text -> (Maybe Text) -> Name
- Data.Gedcom: NameType :: Text -> NameType
- Data.Gedcom: NationalID :: Text -> IndividualAttributeType
- Data.Gedcom: NationalOrigin :: Text -> IndividualAttributeType
- Data.Gedcom: Naturalization :: IndividualEventType
- Data.Gedcom: Note :: Text -> [UserReference] -> Maybe RIN -> [SourceCitation] -> Maybe ChangeDate -> Note
- Data.Gedcom: Occupation :: Text -> IndividualAttributeType
- Data.Gedcom: Ordination :: IndividualEventType
- Data.Gedcom: PersonalName :: Name -> Maybe NameType -> PersonalNamePieces -> [PhoneticName] -> [RomanizedName] -> PersonalName
- Data.Gedcom: PersonalNamePieces :: [Text] -> [Text] -> [Text] -> [Text] -> [Text] -> [Text] -> [GDRef Note] -> [SourceCitation] -> PersonalNamePieces
- Data.Gedcom: PhoneticName :: Name -> PhoneticType -> PersonalNamePieces -> PhoneticName
- Data.Gedcom: PhoneticPlaceName :: PhoneticType -> [Text] -> PhoneticPlaceName
- Data.Gedcom: PhoneticType :: Text -> PhoneticType
- Data.Gedcom: PhysicalDescription :: Text -> IndividualAttributeType
- Data.Gedcom: Pinyin :: RomanType
- Data.Gedcom: Place :: [Text] -> Maybe [Text] -> Maybe PhoneticPlaceName -> Maybe RomanPlaceName -> Maybe MapCoord -> [GDRef Note] -> Place
- Data.Gedcom: Possessions :: Text -> IndividualAttributeType
- Data.Gedcom: Privacy :: RestrictionNotice
- Data.Gedcom: Probate :: IndividualEventType
- Data.Gedcom: Proven :: ChildLinkStatus
- Data.Gedcom: QualityAssessment :: Word -> QualityAssessment
- Data.Gedcom: RFN :: Text -> RFN
- Data.Gedcom: RIN :: Text -> RIN
- Data.Gedcom: Religion :: Text -> IndividualAttributeType
- Data.Gedcom: Repository :: Text -> Maybe Address -> [GDRef Note] -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> Repository
- Data.Gedcom: RepositoryCitation :: Maybe (GDRef Repository) -> [GDRef Note] -> Maybe CallNumber -> RepositoryCitation
- Data.Gedcom: Residence :: FamilyEventType
- Data.Gedcom: ResidesAt :: IndividualAttributeType
- Data.Gedcom: Retirement :: IndividualEventType
- Data.Gedcom: Romaji :: RomanType
- Data.Gedcom: RomanPlaceName :: RomanType -> [Text] -> RomanPlaceName
- Data.Gedcom: RomanType :: Text -> RomanType
- Data.Gedcom: RomanizedName :: Name -> RomanType -> PersonalNamePieces -> RomanizedName
- Data.Gedcom: Sealing :: Pedigree
- Data.Gedcom: SocialSecurity :: Text -> IndividualAttributeType
- Data.Gedcom: Source :: Maybe SourceData -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> [RepositoryCitation] -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> [GDRef Note] -> [GDRef Multimedia] -> Source
- Data.Gedcom: SourceCitation :: Either SourceDescription (GDRef Source) -> Maybe Text -> [GDRef Multimedia] -> [GDRef Note] -> Maybe QualityAssessment -> SourceCitation
- Data.Gedcom: SourceData :: [SourceRecordedEvent] -> Maybe Text -> [GDRef Note] -> SourceData
- Data.Gedcom: SourceDescription :: Text -> [Text] -> SourceDescription
- Data.Gedcom: SourceRecordedEvent :: [EventType] -> Maybe DatePeriod -> Maybe [Text] -> SourceRecordedEvent
- Data.Gedcom: SpouseToFamilyLink :: GDRef Family -> [GDRef Note] -> SpouseToFamilyLink
- Data.Gedcom: Submission :: Maybe (GDRef Submitter) -> Maybe Text -> Maybe Text -> Maybe Word -> Maybe Word -> Maybe Bool -> Maybe RIN -> [GDRef Note] -> Maybe ChangeDate -> Submission
- Data.Gedcom: Submitter :: Name -> Maybe Address -> Maybe (GDRef Multimedia) -> [Language] -> Maybe RFN -> Maybe RIN -> [GDRef Note] -> Maybe ChangeDate -> Submitter
- Data.Gedcom: Title :: Text -> IndividualAttributeType
- Data.Gedcom: Undetermined :: Sex
- Data.Gedcom: UserReference :: Text -> (Maybe Text) -> UserReference
- Data.Gedcom: WadeGiles :: RomanType
- Data.Gedcom: Wife :: Parent
- Data.Gedcom: Will :: IndividualEventType
- Data.Gedcom: Year :: Int -> Year
- Data.Gedcom: [addressCity] :: Address -> Maybe Text
- Data.Gedcom: [addressContact] :: Address -> ContactDetails
- Data.Gedcom: [addressCountry] :: Address -> Maybe Text
- Data.Gedcom: [addressEmail] :: ContactDetails -> [Text]
- Data.Gedcom: [addressFax] :: ContactDetails -> [Text]
- Data.Gedcom: [addressLines] :: Address -> Text
- Data.Gedcom: [addressPhone] :: ContactDetails -> [Text]
- Data.Gedcom: [addressPostcode] :: Address -> Maybe Text
- Data.Gedcom: [addressState] :: Address -> Maybe Text
- Data.Gedcom: [addressWWW] :: ContactDetails -> [Text]
- Data.Gedcom: [associationCitation] :: Association -> [SourceCitation]
- Data.Gedcom: [associationIndividual] :: Association -> GDRef Individual
- Data.Gedcom: [associationNote] :: Association -> [GDRef Note]
- Data.Gedcom: [associationRelation] :: Association -> Text
- Data.Gedcom: [childLinkFamily] :: ChildToFamilyLink -> GDRef Family
- Data.Gedcom: [childLinkNote] :: ChildToFamilyLink -> [GDRef Note]
- Data.Gedcom: [childLinkPedigree] :: ChildToFamilyLink -> Maybe Pedigree
- Data.Gedcom: [childLinkStatus] :: ChildToFamilyLink -> Maybe ChildLinkStatus
- Data.Gedcom: [citeMultimedia] :: SourceCitation -> [GDRef Multimedia]
- Data.Gedcom: [citeNote] :: SourceCitation -> [GDRef Note]
- Data.Gedcom: [citePage] :: SourceCitation -> Maybe Text
- Data.Gedcom: [citeQuality] :: SourceCitation -> Maybe QualityAssessment
- Data.Gedcom: [citeSource] :: SourceCitation -> Either SourceDescription (GDRef Source)
- Data.Gedcom: [corpAddress] :: Corp -> Maybe Address
- Data.Gedcom: [corpName] :: Corp -> Text
- Data.Gedcom: [eventDetailAddress] :: EventDetail -> Maybe Address
- Data.Gedcom: [eventDetailAgency] :: EventDetail -> Maybe Text
- Data.Gedcom: [eventDetailCause] :: EventDetail -> Maybe Text
- Data.Gedcom: [eventDetailDate] :: EventDetail -> Maybe DateValue
- Data.Gedcom: [eventDetailMultimedia] :: EventDetail -> [GDRef Multimedia]
- Data.Gedcom: [eventDetailNote] :: EventDetail -> [GDRef Note]
- Data.Gedcom: [eventDetailPlace] :: EventDetail -> Maybe Place
- Data.Gedcom: [eventDetailReligion] :: EventDetail -> Maybe Text
- Data.Gedcom: [eventDetailRestrictionNotice] :: EventDetail -> Maybe RestrictionNotice
- Data.Gedcom: [eventDetailSourceCitation] :: EventDetail -> [SourceCitation]
- Data.Gedcom: [eventDetailType] :: EventDetail -> Maybe Text
- Data.Gedcom: [familyChangeDate] :: Family -> Maybe ChangeDate
- Data.Gedcom: [familyChildren] :: Family -> [GDRef Individual]
- Data.Gedcom: [familyEventDetailAgeHusband] :: FamilyEventDetail -> Maybe Word
- Data.Gedcom: [familyEventDetailAgeWife] :: FamilyEventDetail -> Maybe Word
- Data.Gedcom: [familyEventDetailDetail] :: FamilyEventDetail -> EventDetail
- Data.Gedcom: [familyEventDetail] :: FamilyEvent -> FamilyEventDetail
- Data.Gedcom: [familyEventType] :: FamilyEvent -> FamilyEventType
- Data.Gedcom: [familyEvent] :: Family -> [FamilyEvent]
- Data.Gedcom: [familyHusband] :: Family -> Maybe (GDRef Individual)
- Data.Gedcom: [familyMultimedia] :: Family -> [GDRef Multimedia]
- Data.Gedcom: [familyNote] :: Family -> [GDRef Note]
- Data.Gedcom: [familyRIN] :: Family -> Maybe RIN
- Data.Gedcom: [familyRestrictionNotice] :: Family -> Maybe RestrictionNotice
- Data.Gedcom: [familySourceCitation] :: Family -> [SourceCitation]
- Data.Gedcom: [familySubitter] :: Family -> [GDRef Submitter]
- Data.Gedcom: [familyTotalChildren] :: Family -> Maybe Word
- Data.Gedcom: [familyUserReference] :: Family -> [UserReference]
- Data.Gedcom: [familyWife] :: Family -> Maybe (GDRef Individual)
- Data.Gedcom: [gedcomFamily] :: Gedcom -> [GDRef Family]
- Data.Gedcom: [gedcomForm] :: GedcomFormat -> GedcomForm
- Data.Gedcom: [gedcomHeader] :: Gedcom -> Header
- Data.Gedcom: [gedcomIndividual] :: Gedcom -> [GDRef Individual]
- Data.Gedcom: [gedcomMultimedia] :: Gedcom -> [GDRef Multimedia]
- Data.Gedcom: [gedcomNote] :: Gedcom -> [GDRef Note]
- Data.Gedcom: [gedcomRepository] :: Gedcom -> [GDRef Repository]
- Data.Gedcom: [gedcomSource] :: Gedcom -> [GDRef Source]
- Data.Gedcom: [gedcomSubmitter] :: Gedcom -> [GDRef Submitter]
- Data.Gedcom: [gedcomVersion] :: GedcomFormat -> Text
- Data.Gedcom: [headerCharset] :: Header -> Charset
- Data.Gedcom: [headerCopyright] :: Header -> Maybe Text
- Data.Gedcom: [headerDate] :: Header -> Maybe UTCTime
- Data.Gedcom: [headerDestination] :: Header -> Maybe Text
- Data.Gedcom: [headerFile] :: Header -> Maybe FilePath
- Data.Gedcom: [headerGedcomFormat] :: Header -> GedcomFormat
- Data.Gedcom: [headerLang] :: Header -> Maybe Language
- Data.Gedcom: [headerNote] :: Header -> Maybe Text
- Data.Gedcom: [headerPlaceForm] :: Header -> Maybe [Text]
- Data.Gedcom: [headerSourceCorp] :: HeaderSource -> Maybe Corp
- Data.Gedcom: [headerSourceDataCopyright] :: HeaderSourceData -> Maybe Text
- Data.Gedcom: [headerSourceDataDate] :: HeaderSourceData -> Maybe UTCTime
- Data.Gedcom: [headerSourceDataName] :: HeaderSourceData -> Text
- Data.Gedcom: [headerSourceData] :: HeaderSource -> Maybe HeaderSourceData
- Data.Gedcom: [headerSourceName] :: HeaderSource -> Maybe Text
- Data.Gedcom: [headerSourceSystemID] :: HeaderSource -> Text
- Data.Gedcom: [headerSourceVersion] :: HeaderSource -> Maybe Text
- Data.Gedcom: [headerSource] :: Header -> HeaderSource
- Data.Gedcom: [headerSubmission] :: Header -> Maybe (GDRef Submission)
- Data.Gedcom: [headerSubmitter] :: Header -> GDRef Submitter
- Data.Gedcom: [individualAFN] :: Individual -> Maybe AFN
- Data.Gedcom: [individualAlias] :: Individual -> [GDRef Individual]
- Data.Gedcom: [individualAncestorInterest] :: Individual -> [GDRef Submitter]
- Data.Gedcom: [individualAssociation] :: Individual -> [Association]
- Data.Gedcom: [individualAttribute] :: Individual -> [IndividualAttribute]
- Data.Gedcom: [individualChangeDate] :: Individual -> Maybe ChangeDate
- Data.Gedcom: [individualChildToFamilyLink] :: Individual -> [ChildToFamilyLink]
- Data.Gedcom: [individualDescendantInterest] :: Individual -> [GDRef Submitter]
- Data.Gedcom: [individualEventDetailAge] :: IndividualEventDetail -> Maybe Word
- Data.Gedcom: [individualEventDetailDetail] :: IndividualEventDetail -> EventDetail
- Data.Gedcom: [individualEventDetail] :: IndividualEvent -> IndividualEventDetail
- Data.Gedcom: [individualEventType] :: IndividualEvent -> IndividualEventType
- Data.Gedcom: [individualEvent] :: Individual -> [IndividualEvent]
- Data.Gedcom: [individualMultimedia] :: Individual -> [GDRef Multimedia]
- Data.Gedcom: [individualName] :: Individual -> Maybe PersonalName
- Data.Gedcom: [individualNote] :: Individual -> [GDRef Note]
- Data.Gedcom: [individualRFN] :: Individual -> Maybe RFN
- Data.Gedcom: [individualRIN] :: Individual -> Maybe RIN
- Data.Gedcom: [individualRestrictionNotice] :: Individual -> Maybe RestrictionNotice
- Data.Gedcom: [individualSex] :: Individual -> Maybe Sex
- Data.Gedcom: [individualSourceCitation] :: Individual -> [SourceCitation]
- Data.Gedcom: [individualSpouseToFamilyLink] :: Individual -> [SpouseToFamilyLink]
- Data.Gedcom: [individualSubmitter] :: Individual -> [GDRef Submitter]
- Data.Gedcom: [individualUserReference] :: Individual -> [UserReference]
- Data.Gedcom: [multimediaChangeDate] :: Multimedia -> Maybe ChangeDate
- Data.Gedcom: [multimediaFileFormat] :: MultimediaFile -> MultimediaFormat
- Data.Gedcom: [multimediaFileLink] :: MultimediaFile -> Text
- Data.Gedcom: [multimediaFile] :: Multimedia -> [MultimediaFile]
- Data.Gedcom: [multimediaNote] :: Multimedia -> [GDRef Note]
- Data.Gedcom: [multimediaRIN] :: Multimedia -> Maybe RIN
- Data.Gedcom: [multimediaSourceCitation] :: Multimedia -> [SourceCitation]
- Data.Gedcom: [multimediaTitl] :: Multimedia -> Maybe Text
- Data.Gedcom: [multimediaTitle] :: MultimediaFile -> Maybe Text
- Data.Gedcom: [multimediaUserReference] :: Multimedia -> [UserReference]
- Data.Gedcom: [namePieceGiven] :: PersonalNamePieces -> [Text]
- Data.Gedcom: [namePieceNameNote] :: PersonalNamePieces -> [GDRef Note]
- Data.Gedcom: [namePieceNickname] :: PersonalNamePieces -> [Text]
- Data.Gedcom: [namePiecePrefix] :: PersonalNamePieces -> [Text]
- Data.Gedcom: [namePieceSuffix] :: PersonalNamePieces -> [Text]
- Data.Gedcom: [namePieceSurnamePrefix] :: PersonalNamePieces -> [Text]
- Data.Gedcom: [namePieceSurname] :: PersonalNamePieces -> [Text]
- Data.Gedcom: [namePirceSourceCitation] :: PersonalNamePieces -> [SourceCitation]
- Data.Gedcom: [noteChangeDate] :: Note -> Maybe ChangeDate
- Data.Gedcom: [noteRIN] :: Note -> Maybe RIN
- Data.Gedcom: [noteSourceCitation] :: Note -> [SourceCitation]
- Data.Gedcom: [noteText] :: Note -> Text
- Data.Gedcom: [noteUserReference] :: Note -> [UserReference]
- Data.Gedcom: [personalNameName] :: PersonalName -> Name
- Data.Gedcom: [personalNamePhonetic] :: PersonalName -> [PhoneticName]
- Data.Gedcom: [personalNamePieces] :: PersonalName -> PersonalNamePieces
- Data.Gedcom: [personalNameRoman] :: PersonalName -> [RomanizedName]
- Data.Gedcom: [personalNameType] :: PersonalName -> Maybe NameType
- Data.Gedcom: [phoneticName] :: PhoneticName -> Name
- Data.Gedcom: [phoneticPieces] :: PhoneticName -> PersonalNamePieces
- Data.Gedcom: [phoneticType] :: PhoneticName -> PhoneticType
- Data.Gedcom: [placeForm] :: Place -> Maybe [Text]
- Data.Gedcom: [placeMap] :: Place -> Maybe MapCoord
- Data.Gedcom: [placeName] :: Place -> [Text]
- Data.Gedcom: [placeNote] :: Place -> [GDRef Note]
- Data.Gedcom: [placePhonetic] :: Place -> Maybe PhoneticPlaceName
- Data.Gedcom: [placeRoman] :: Place -> Maybe RomanPlaceName
- Data.Gedcom: [repoCiteCallNumber] :: RepositoryCitation -> Maybe CallNumber
- Data.Gedcom: [repoCiteNote] :: RepositoryCitation -> [GDRef Note]
- Data.Gedcom: [repoCiteRepository] :: RepositoryCitation -> Maybe (GDRef Repository)
- Data.Gedcom: [repositoryAddress] :: Repository -> Maybe Address
- Data.Gedcom: [repositoryChangeDate] :: Repository -> Maybe ChangeDate
- Data.Gedcom: [repositoryName] :: Repository -> Text
- Data.Gedcom: [repositoryNote] :: Repository -> [GDRef Note]
- Data.Gedcom: [repositoryRIN] :: Repository -> Maybe RIN
- Data.Gedcom: [repositoryUserReference] :: Repository -> [UserReference]
- Data.Gedcom: [romanziedName] :: RomanizedName -> Name
- Data.Gedcom: [romanziedPieces] :: RomanizedName -> PersonalNamePieces
- Data.Gedcom: [romanziedType] :: RomanizedName -> RomanType
- Data.Gedcom: [sourceAuthor] :: Source -> Maybe Text
- Data.Gedcom: [sourceChangeDate] :: Source -> Maybe ChangeDate
- Data.Gedcom: [sourceDataAgency] :: SourceData -> Maybe Text
- Data.Gedcom: [sourceDataEventsRecorded] :: SourceData -> [SourceRecordedEvent]
- Data.Gedcom: [sourceDataNote] :: SourceData -> [GDRef Note]
- Data.Gedcom: [sourceData] :: Source -> Maybe SourceData
- Data.Gedcom: [sourceMultimedia] :: Source -> [GDRef Multimedia]
- Data.Gedcom: [sourceNote] :: Source -> [GDRef Note]
- Data.Gedcom: [sourcePublicationFacts] :: Source -> Maybe Text
- Data.Gedcom: [sourceRIN] :: Source -> Maybe RIN
- Data.Gedcom: [sourceRecordedDate] :: SourceRecordedEvent -> Maybe DatePeriod
- Data.Gedcom: [sourceRecordedEventType] :: SourceRecordedEvent -> [EventType]
- Data.Gedcom: [sourceRecordedPlace] :: SourceRecordedEvent -> Maybe [Text]
- Data.Gedcom: [sourceRepositoryCitations] :: Source -> [RepositoryCitation]
- Data.Gedcom: [sourceShortTitle] :: Source -> Maybe Text
- Data.Gedcom: [sourceText] :: Source -> Maybe Text
- Data.Gedcom: [sourceTitle] :: Source -> Maybe Text
- Data.Gedcom: [sourceUserReference] :: Source -> [UserReference]
- Data.Gedcom: [spouseToFamilyLinkFamily] :: SpouseToFamilyLink -> GDRef Family
- Data.Gedcom: [spouseToFamilyLinkNote] :: SpouseToFamilyLink -> [GDRef Note]
- Data.Gedcom: [submissionAncestorGenerations] :: Submission -> Maybe Word
- Data.Gedcom: [submissionChangeDate] :: Submission -> Maybe ChangeDate
- Data.Gedcom: [submissionDescendentGenerations] :: Submission -> Maybe Word
- Data.Gedcom: [submissionFamilyFile] :: Submission -> Maybe Text
- Data.Gedcom: [submissionNote] :: Submission -> [GDRef Note]
- Data.Gedcom: [submissionOrdinanceProcessing] :: Submission -> Maybe Bool
- Data.Gedcom: [submissionRIN] :: Submission -> Maybe RIN
- Data.Gedcom: [submissionSubmitter] :: Submission -> Maybe (GDRef Submitter)
- Data.Gedcom: [submissionTempleCode] :: Submission -> Maybe Text
- Data.Gedcom: [submitterAddress] :: Submitter -> Maybe Address
- Data.Gedcom: [submitterChangeDate] :: Submitter -> Maybe ChangeDate
- Data.Gedcom: [submitterLang] :: Submitter -> [Language]
- Data.Gedcom: [submitterMedia] :: Submitter -> Maybe (GDRef Multimedia)
- Data.Gedcom: [submitterName] :: Submitter -> Name
- Data.Gedcom: [submitterNote] :: Submitter -> [GDRef Note]
- Data.Gedcom: [submitterRFN] :: Submitter -> Maybe RFN
- Data.Gedcom: [submitterRIN] :: Submitter -> Maybe RIN
- Data.Gedcom: data Address
- Data.Gedcom: data AdoptionDetail
- Data.Gedcom: data Association
- Data.Gedcom: data Calendar
- Data.Gedcom: data CallNumber
- Data.Gedcom: data ChangeDate
- Data.Gedcom: data Charset
- Data.Gedcom: data ChildLinkStatus
- Data.Gedcom: data ChildToFamilyLink
- Data.Gedcom: data ContactDetails
- Data.Gedcom: data Corp
- Data.Gedcom: data Date
- Data.Gedcom: data DateApprox
- Data.Gedcom: data DatePeriod
- Data.Gedcom: data DateRange
- Data.Gedcom: data DateValue
- Data.Gedcom: data EventDetail
- Data.Gedcom: data EventType
- Data.Gedcom: data Family
- Data.Gedcom: data FamilyEvent
- Data.Gedcom: data FamilyEventDetail
- Data.Gedcom: data FamilyEventType
- Data.Gedcom: data Gedcom
- Data.Gedcom: data GedcomForm
- Data.Gedcom: data GedcomFormat
- Data.Gedcom: data Header
- Data.Gedcom: data HeaderSource
- Data.Gedcom: data HeaderSourceData
- Data.Gedcom: data Individual
- Data.Gedcom: data IndividualAttribute
- Data.Gedcom: data IndividualAttributeType
- Data.Gedcom: data IndividualEvent
- Data.Gedcom: data IndividualEventDetail
- Data.Gedcom: data IndividualEventType
- Data.Gedcom: data MapCoord
- Data.Gedcom: data Multimedia
- Data.Gedcom: data MultimediaFile
- Data.Gedcom: data MultimediaFileFormat
- Data.Gedcom: data MultimediaFormat
- Data.Gedcom: data MultimediaType
- Data.Gedcom: data Name
- Data.Gedcom: data NameType
- Data.Gedcom: data Note
- Data.Gedcom: data Parent
- Data.Gedcom: data Pedigree
- Data.Gedcom: data PersonalName
- Data.Gedcom: data PersonalNamePieces
- Data.Gedcom: data PhoneticName
- Data.Gedcom: data PhoneticPlaceName
- Data.Gedcom: data PhoneticType
- Data.Gedcom: data Place
- Data.Gedcom: data Repository
- Data.Gedcom: data RepositoryCitation
- Data.Gedcom: data RestrictionNotice
- Data.Gedcom: data RomanPlaceName
- Data.Gedcom: data RomanType
- Data.Gedcom: data RomanizedName
- Data.Gedcom: data Sex
- Data.Gedcom: data Source
- Data.Gedcom: data SourceCitation
- Data.Gedcom: data SourceData
- Data.Gedcom: data SourceDescription
- Data.Gedcom: data SourceRecordedEvent
- Data.Gedcom: data SpouseToFamilyLink
- Data.Gedcom: data Submission
- Data.Gedcom: data Submitter
- Data.Gedcom: data UserReference
- Data.Gedcom: newtype AFN
- Data.Gedcom: newtype Language
- Data.Gedcom: newtype Latitude
- Data.Gedcom: newtype Longitude
- Data.Gedcom: newtype QualityAssessment
- Data.Gedcom: newtype RFN
- Data.Gedcom: newtype RIN
- Data.Gedcom: newtype Year
+ Data.Gedcom.Internal.Common: (<&>) :: Functor f => f a -> (a -> b) -> f b
+ Data.Gedcom.Internal.Common: dateExact :: Parser (Int, Word, Int)
+ Data.Gedcom.Internal.Common: infixl 1 <&>
+ Data.Gedcom.Internal.Common: month :: Parser Word
+ Data.Gedcom.Internal.Common: monthFr :: Parser Word
+ Data.Gedcom.Internal.Common: monthHeb :: Parser Word
+ Data.Gedcom.Internal.Common: timeToPicos :: (Int, Int, Int, Double) -> DiffTime
+ Data.Gedcom.Internal.Common: timeValue :: Parser (Maybe (Int, Int, Int, Double))
+ Data.Gedcom.Internal.Common: trim :: Text -> Text
+ Data.Gedcom.Internal.Common: type Parser = Parsec Void Text
+ Data.Gedcom.Internal.Common: withDefault :: Alternative f => a -> f a -> f a
+ Data.Gedcom.Internal.Common: yearGreg :: Parser Int
+ Data.Gedcom.Internal.CoreTypes: DuplicateRef :: Text -> GDError
+ Data.Gedcom.Internal.CoreTypes: FormatError :: Text -> GDError
+ Data.Gedcom.Internal.CoreTypes: GDEscape :: Text -> GDEscape
+ Data.Gedcom.Internal.CoreTypes: GDLevel :: Int -> GDLevel
+ Data.Gedcom.Internal.CoreTypes: GDLine :: GDLevel -> (Maybe GDXRefID) -> GDTag -> (Maybe GDLineValue) -> GDLine
+ Data.Gedcom.Internal.CoreTypes: GDLineItem :: [(Maybe GDEscape, Text)] -> GDLineItem
+ Data.Gedcom.Internal.CoreTypes: GDLineItemV :: GDLineItem -> GDLineValue
+ Data.Gedcom.Internal.CoreTypes: GDRoot :: [GDTree] -> GDRoot
+ Data.Gedcom.Internal.CoreTypes: GDStructure :: a -> GDRef a
+ Data.Gedcom.Internal.CoreTypes: GDTag :: Text -> GDTag
+ Data.Gedcom.Internal.CoreTypes: GDTree :: GDLine -> [GDTree] -> GDTree
+ Data.Gedcom.Internal.CoreTypes: GDXRef :: GDXRefID -> GDRef a
+ Data.Gedcom.Internal.CoreTypes: GDXRefID :: Text -> GDXRefID
+ Data.Gedcom.Internal.CoreTypes: GDXRefIDV :: GDXRefID -> GDLineValue
+ Data.Gedcom.Internal.CoreTypes: LineFormatError :: Text -> GDError
+ Data.Gedcom.Internal.CoreTypes: RefNotPresent :: GDXRefID -> GDRefError
+ Data.Gedcom.Internal.CoreTypes: RequiredRef :: Text -> GDError
+ Data.Gedcom.Internal.CoreTypes: TagError :: Text -> GDError
+ Data.Gedcom.Internal.CoreTypes: UnexpectedRef :: Text -> GDError
+ Data.Gedcom.Internal.CoreTypes: WrongRefType :: TypeRep -> TypeRep -> GDRefError
+ Data.Gedcom.Internal.CoreTypes: data GDError
+ Data.Gedcom.Internal.CoreTypes: data GDLine
+ Data.Gedcom.Internal.CoreTypes: data GDLineValue
+ Data.Gedcom.Internal.CoreTypes: data GDRef a
+ Data.Gedcom.Internal.CoreTypes: data GDRefError
+ Data.Gedcom.Internal.CoreTypes: data GDRoot
+ Data.Gedcom.Internal.CoreTypes: data GDTree
+ Data.Gedcom.Internal.CoreTypes: gdFilterEscapes :: [GDEscape] -> [(Maybe GDEscape, Text)] -> [(Maybe GDEscape, Text)]
+ Data.Gedcom.Internal.CoreTypes: gdIgnoreEscapes :: [(Maybe GDEscape, Text)] -> Text
+ Data.Gedcom.Internal.CoreTypes: gdLineData :: GDLineItem -> [(Maybe GDEscape, Text)]
+ Data.Gedcom.Internal.CoreTypes: gdTrimLineItem :: GDLineItem -> GDLineItem
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Base.Monoid Data.Gedcom.Internal.CoreTypes.GDLineItem
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDEscape
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDLevel
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDLine
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDLineItem
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDLineValue
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDRoot
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDTag
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDTree
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq Data.Gedcom.Internal.CoreTypes.GDXRefID
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Gedcom.Internal.CoreTypes.GDRef a)
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Ord Data.Gedcom.Internal.CoreTypes.GDLevel
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Ord Data.Gedcom.Internal.CoreTypes.GDTag
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Classes.Ord Data.Gedcom.Internal.CoreTypes.GDXRefID
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Num.Num Data.Gedcom.Internal.CoreTypes.GDLevel
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDError
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDEscape
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDLevel
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDLine
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDLineItem
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDLineValue
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDRefError
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDRoot
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDTag
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDTree
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show Data.Gedcom.Internal.CoreTypes.GDXRefID
+ Data.Gedcom.Internal.CoreTypes: instance GHC.Show.Show a => GHC.Show.Show (Data.Gedcom.Internal.CoreTypes.GDRef a)
+ Data.Gedcom.Internal.CoreTypes: newtype GDEscape
+ Data.Gedcom.Internal.CoreTypes: newtype GDLevel
+ Data.Gedcom.Internal.CoreTypes: newtype GDLineItem
+ Data.Gedcom.Internal.CoreTypes: newtype GDTag
+ Data.Gedcom.Internal.CoreTypes: newtype GDXRefID
+ Data.Gedcom.Internal.LineParser: gdDelim :: Parser (Maybe Char)
+ Data.Gedcom.Internal.LineParser: gdRoot :: Parser GDRoot
+ Data.Gedcom.Internal.ParseMonads: addReference :: Typeable a => GDXRefID -> a -> StructureMonad ()
+ Data.Gedcom.Internal.ParseMonads: data MultiMonad a
+ Data.Gedcom.Internal.ParseMonads: data StructureMonad a
+ Data.Gedcom.Internal.ParseMonads: instance Control.Monad.Error.Class.MonadError Data.Gedcom.Internal.CoreTypes.GDError Data.Gedcom.Internal.ParseMonads.MultiMonad
+ Data.Gedcom.Internal.ParseMonads: instance Control.Monad.Error.Class.MonadError Data.Gedcom.Internal.CoreTypes.GDError Data.Gedcom.Internal.ParseMonads.StructureMonad
+ Data.Gedcom.Internal.ParseMonads: instance GHC.Base.Applicative Data.Gedcom.Internal.ParseMonads.MultiMonad
+ Data.Gedcom.Internal.ParseMonads: instance GHC.Base.Applicative Data.Gedcom.Internal.ParseMonads.StructureMonad
+ Data.Gedcom.Internal.ParseMonads: instance GHC.Base.Functor Data.Gedcom.Internal.ParseMonads.MultiMonad
+ Data.Gedcom.Internal.ParseMonads: instance GHC.Base.Functor Data.Gedcom.Internal.ParseMonads.StructureMonad
+ Data.Gedcom.Internal.ParseMonads: instance GHC.Base.Monad Data.Gedcom.Internal.ParseMonads.MultiMonad
+ Data.Gedcom.Internal.ParseMonads: instance GHC.Base.Monad Data.Gedcom.Internal.ParseMonads.StructureMonad
+ Data.Gedcom.Internal.ParseMonads: parseMulti :: StructureParser a -> MultiMonad [a]
+ Data.Gedcom.Internal.ParseMonads: parseOptional :: StructureParser a -> MultiMonad (Maybe a)
+ Data.Gedcom.Internal.ParseMonads: parseRequired :: GDTag -> StructureParser a -> MultiMonad a
+ Data.Gedcom.Internal.ParseMonads: runMultiMonad :: [GDTree] -> MultiMonad a -> StructureMonad a
+ Data.Gedcom.Internal.ParseMonads: runStructure :: StructureMonad a -> (Either GDError a, Map GDXRefID Dynamic)
+ Data.Gedcom.Internal.ParseMonads: type StructureParser a = GDTree The subtree to parse. -> StructureMonad (Either GDTree a) Either parsed structure, or the subtree itself if the subtree doesn't contain the expected GEDCOM structure.
+ Data.Gedcom.Internal.Parser: parseBoolTag :: GDTag -> StructureParser Bool
+ Data.Gedcom.Internal.Parser: parseGedcom :: GDRoot -> (Either GDError Gedcom, Map GDXRefID Dynamic)
+ Data.Gedcom.Internal.Parser: parseHeader :: StructureParser Header
+ Data.Gedcom.Internal.Parser: parseLinkTag :: Typeable a => GDTag -> StructureParser (GDRef a)
+ Data.Gedcom.Internal.Parser: parseListTag :: GDTag -> StructureParser [Text]
+ Data.Gedcom.Internal.Parser: parseNoLinkTag :: Typeable a => GDTag -> NoLinkHandler a -> StructureParser a
+ Data.Gedcom.Internal.Parser: parseTag :: Typeable a => GDTag -> NoLinkHandler a -> StructureParser (GDRef a)
+ Data.Gedcom.Internal.Parser: parseTextTag :: GDTag -> StructureParser Text
+ Data.Gedcom.Internal.Parser: parseWordTag :: GDTag -> StructureParser Word
+ Data.Gedcom.Structure: AFN :: Text -> AFN
+ Data.Gedcom.Structure: AKA :: NameType
+ Data.Gedcom.Structure: Address :: Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> ContactDetails -> Address
+ Data.Gedcom.Structure: Adopted :: Pedigree
+ Data.Gedcom.Structure: Adoption :: (Maybe AdoptionDetail) -> IndividualEventType
+ Data.Gedcom.Structure: AdoptionDetail :: (GDRef Family) -> (Maybe Parent) -> AdoptionDetail
+ Data.Gedcom.Structure: Annuled :: FamilyEventType
+ Data.Gedcom.Structure: Association :: GDRef Individual -> Text -> [SourceCitation] -> [GDRef Note] -> Association
+ Data.Gedcom.Structure: Baptism :: IndividualEventType
+ Data.Gedcom.Structure: BarMitzvah :: IndividualEventType
+ Data.Gedcom.Structure: BasMitzvah :: IndividualEventType
+ Data.Gedcom.Structure: Birth :: (Maybe (GDRef Family)) -> IndividualEventType
+ Data.Gedcom.Structure: BirthName :: NameType
+ Data.Gedcom.Structure: Blessing :: IndividualEventType
+ Data.Gedcom.Structure: BothParents :: Parent
+ Data.Gedcom.Structure: Burial :: IndividualEventType
+ Data.Gedcom.Structure: ByBirth :: Pedigree
+ Data.Gedcom.Structure: CallNumber :: Text -> (Maybe MultimediaType) -> CallNumber
+ Data.Gedcom.Structure: Caste :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Census :: EventType
+ Data.Gedcom.Structure: Challenged :: ChildLinkStatus
+ Data.Gedcom.Structure: ChangeDate :: UTCTime -> (Maybe (GDRef Note)) -> ChangeDate
+ Data.Gedcom.Structure: Charset :: Text -> (Maybe Text) -> Charset
+ Data.Gedcom.Structure: ChildToFamilyLink :: GDRef Family -> Maybe Pedigree -> Maybe ChildLinkStatus -> [GDRef Note] -> ChildToFamilyLink
+ Data.Gedcom.Structure: Christening :: (Maybe (GDRef Family)) -> IndividualEventType
+ Data.Gedcom.Structure: ChristeningAdult :: IndividualEventType
+ Data.Gedcom.Structure: Confidential :: RestrictionNotice
+ Data.Gedcom.Structure: Confirmation :: IndividualEventType
+ Data.Gedcom.Structure: ContactDetails :: [Text] -> [Text] -> [Text] -> [Text] -> ContactDetails
+ Data.Gedcom.Structure: Corp :: Text -> Maybe Address -> Corp
+ Data.Gedcom.Structure: Cremation :: IndividualEventType
+ Data.Gedcom.Structure: Date :: Calendar -> (Maybe Word) -> (Maybe Word) -> Year -> Date
+ Data.Gedcom.Structure: DateAbout :: Date -> DateApprox
+ Data.Gedcom.Structure: DateAfter :: Date -> DateRange
+ Data.Gedcom.Structure: DateApproxV :: DateApprox -> DateValue
+ Data.Gedcom.Structure: DateBefore :: Date -> DateRange
+ Data.Gedcom.Structure: DateBetween :: Date -> Date -> DateRange
+ Data.Gedcom.Structure: DateCalculated :: Date -> DateApprox
+ Data.Gedcom.Structure: DateEstimated :: Date -> DateApprox
+ Data.Gedcom.Structure: DateFrom :: Date -> (Maybe Date) -> DatePeriod
+ Data.Gedcom.Structure: DatePeriodV :: DatePeriod -> DateValue
+ Data.Gedcom.Structure: DatePhrase :: (Maybe Date) -> Text -> DateValue
+ Data.Gedcom.Structure: DateRangeV :: DateRange -> DateValue
+ Data.Gedcom.Structure: DateTo :: Date -> DatePeriod
+ Data.Gedcom.Structure: DateV :: Date -> DateValue
+ Data.Gedcom.Structure: Death :: IndividualEventType
+ Data.Gedcom.Structure: Disproved :: ChildLinkStatus
+ Data.Gedcom.Structure: Divorce :: FamilyEventType
+ Data.Gedcom.Structure: DivorceFiled :: FamilyEventType
+ Data.Gedcom.Structure: Education :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Emigration :: IndividualEventType
+ Data.Gedcom.Structure: Engagement :: FamilyEventType
+ Data.Gedcom.Structure: EventDetail :: Maybe Text -> Maybe DateValue -> Maybe Place -> Maybe Address -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe RestrictionNotice -> [GDRef Note] -> [SourceCitation] -> [GDRef Multimedia] -> EventDetail
+ Data.Gedcom.Structure: EventType :: Text -> EventType
+ Data.Gedcom.Structure: Fact :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: FamCensus :: FamilyEventType
+ Data.Gedcom.Structure: Family :: Maybe RestrictionNotice -> [FamilyEvent] -> Maybe (GDRef Individual) -> Maybe (GDRef Individual) -> [GDRef Individual] -> Maybe Word -> [GDRef Submitter] -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> [GDRef Note] -> [SourceCitation] -> [GDRef Multimedia] -> Family
+ Data.Gedcom.Structure: FamilyEvent :: FamilyEventType -> FamilyEventDetail -> FamilyEvent
+ Data.Gedcom.Structure: FamilyEventDetail :: Maybe Word -> Maybe Word -> EventDetail -> FamilyEventDetail
+ Data.Gedcom.Structure: FamilyEventType :: Text -> FamilyEventType
+ Data.Gedcom.Structure: FamilyEventTypeV :: FamilyEventType -> EventType
+ Data.Gedcom.Structure: Female :: Sex
+ Data.Gedcom.Structure: FirstCommunion :: IndividualEventType
+ Data.Gedcom.Structure: Foster :: Pedigree
+ Data.Gedcom.Structure: French :: Calendar
+ Data.Gedcom.Structure: Gedcom :: Header -> [GDRef Family] -> [GDRef Individual] -> [GDRef Multimedia] -> [GDRef Note] -> [GDRef Repository] -> [GDRef Source] -> [GDRef Submitter] -> Gedcom
+ Data.Gedcom.Structure: GedcomFormat :: Text -> GedcomForm -> GedcomFormat
+ Data.Gedcom.Structure: GedcomLineageLinked :: GedcomForm
+ Data.Gedcom.Structure: GedcomUnsupported :: Text -> GedcomForm
+ Data.Gedcom.Structure: Graduation :: IndividualEventType
+ Data.Gedcom.Structure: Gregorian :: Calendar
+ Data.Gedcom.Structure: Hangul :: PhoneticType
+ Data.Gedcom.Structure: Header :: HeaderSource -> Maybe Text -> Maybe UTCTime -> GDRef Submitter -> Maybe (GDRef Submission) -> Maybe FilePath -> Maybe Text -> GedcomFormat -> Charset -> Maybe Language -> Maybe [Text] -> Maybe Text -> Header
+ Data.Gedcom.Structure: HeaderSource :: Text -> Maybe Text -> Maybe Text -> Maybe Corp -> Maybe HeaderSourceData -> HeaderSource
+ Data.Gedcom.Structure: HeaderSourceData :: Text -> Maybe UTCTime -> Maybe Text -> HeaderSourceData
+ Data.Gedcom.Structure: Hebrew :: Calendar
+ Data.Gedcom.Structure: Husband :: Parent
+ Data.Gedcom.Structure: Immigrant :: NameType
+ Data.Gedcom.Structure: Immigration :: IndividualEventType
+ Data.Gedcom.Structure: Individual :: Maybe RestrictionNotice -> Maybe PersonalName -> Maybe Sex -> [IndividualEvent] -> [IndividualAttribute] -> [ChildToFamilyLink] -> [SpouseToFamilyLink] -> [GDRef Submitter] -> [Association] -> [GDRef Individual] -> [GDRef Submitter] -> [GDRef Submitter] -> Maybe RFN -> Maybe AFN -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> [GDRef Note] -> [SourceCitation] -> [GDRef Multimedia] -> Individual
+ Data.Gedcom.Structure: IndividualAttribute :: IndividualAttributeType -> (IndividualEventDetail) -> IndividualAttribute
+ Data.Gedcom.Structure: IndividualEvent :: IndividualEventType -> IndividualEventDetail -> IndividualEvent
+ Data.Gedcom.Structure: IndividualEventDetail :: EventDetail -> Maybe Word -> IndividualEventDetail
+ Data.Gedcom.Structure: IndividualEventType :: Text -> IndividualEventType
+ Data.Gedcom.Structure: IndividualEventTypeV :: IndividualEventType -> EventType
+ Data.Gedcom.Structure: IndvCensus :: IndividualEventType
+ Data.Gedcom.Structure: Julian :: Calendar
+ Data.Gedcom.Structure: Kana :: PhoneticType
+ Data.Gedcom.Structure: Language :: Text -> Language
+ Data.Gedcom.Structure: Latitude :: Double -> Latitude
+ Data.Gedcom.Structure: Locked :: RestrictionNotice
+ Data.Gedcom.Structure: Longitude :: Double -> Longitude
+ Data.Gedcom.Structure: MF_BMP :: MultimediaFileFormat
+ Data.Gedcom.Structure: MF_GIF :: MultimediaFileFormat
+ Data.Gedcom.Structure: MF_JPG :: MultimediaFileFormat
+ Data.Gedcom.Structure: MF_OLE :: MultimediaFileFormat
+ Data.Gedcom.Structure: MF_OTHER :: Text -> MultimediaFileFormat
+ Data.Gedcom.Structure: MF_PCX :: MultimediaFileFormat
+ Data.Gedcom.Structure: MF_TIF :: MultimediaFileFormat
+ Data.Gedcom.Structure: MF_WAV :: MultimediaFileFormat
+ Data.Gedcom.Structure: MT_AUDIO :: MultimediaType
+ Data.Gedcom.Structure: MT_BOOK :: MultimediaType
+ Data.Gedcom.Structure: MT_CARD :: MultimediaType
+ Data.Gedcom.Structure: MT_ELECTRONIC :: MultimediaType
+ Data.Gedcom.Structure: MT_FICHE :: MultimediaType
+ Data.Gedcom.Structure: MT_FILM :: MultimediaType
+ Data.Gedcom.Structure: MT_MAGAZINE :: MultimediaType
+ Data.Gedcom.Structure: MT_MANUSCRIPT :: MultimediaType
+ Data.Gedcom.Structure: MT_MAP :: MultimediaType
+ Data.Gedcom.Structure: MT_NEWSPAPER :: MultimediaType
+ Data.Gedcom.Structure: MT_OTHER :: Text -> MultimediaType
+ Data.Gedcom.Structure: MT_PHOTO :: MultimediaType
+ Data.Gedcom.Structure: MT_TOMBSTONE :: MultimediaType
+ Data.Gedcom.Structure: MT_VIDEO :: MultimediaType
+ Data.Gedcom.Structure: Maiden :: NameType
+ Data.Gedcom.Structure: Male :: Sex
+ Data.Gedcom.Structure: MapCoord :: Longitude -> Latitude -> MapCoord
+ Data.Gedcom.Structure: Marriage :: FamilyEventType
+ Data.Gedcom.Structure: MarriageBann :: FamilyEventType
+ Data.Gedcom.Structure: MarriageContract :: FamilyEventType
+ Data.Gedcom.Structure: MarriageLicense :: FamilyEventType
+ Data.Gedcom.Structure: MarriageSettlement :: FamilyEventType
+ Data.Gedcom.Structure: Married :: NameType
+ Data.Gedcom.Structure: Multimedia :: [MultimediaFile] -> Maybe Text -> [UserReference] -> Maybe RIN -> [GDRef Note] -> [SourceCitation] -> Maybe ChangeDate -> Multimedia
+ Data.Gedcom.Structure: MultimediaFile :: Text -> MultimediaFormat -> Maybe Text -> MultimediaFile
+ Data.Gedcom.Structure: MultimediaFormat :: MultimediaFileFormat -> (Maybe MultimediaType) -> MultimediaFormat
+ Data.Gedcom.Structure: NChildren :: Word -> IndividualAttributeType
+ Data.Gedcom.Structure: NMarriages :: Word -> IndividualAttributeType
+ Data.Gedcom.Structure: Name :: Text -> (Maybe Text) -> Name
+ Data.Gedcom.Structure: NameType :: Text -> NameType
+ Data.Gedcom.Structure: NationalID :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: NationalOrigin :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Naturalization :: IndividualEventType
+ Data.Gedcom.Structure: Note :: Text -> [UserReference] -> Maybe RIN -> [SourceCitation] -> Maybe ChangeDate -> Note
+ Data.Gedcom.Structure: Occupation :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Ordination :: IndividualEventType
+ Data.Gedcom.Structure: PersonalName :: Name -> Maybe NameType -> PersonalNamePieces -> [PhoneticName] -> [RomanizedName] -> PersonalName
+ Data.Gedcom.Structure: PersonalNamePieces :: [Text] -> [Text] -> [Text] -> [Text] -> [Text] -> [Text] -> [GDRef Note] -> [SourceCitation] -> PersonalNamePieces
+ Data.Gedcom.Structure: PhoneticName :: Name -> PhoneticType -> PersonalNamePieces -> PhoneticName
+ Data.Gedcom.Structure: PhoneticPlaceName :: PhoneticType -> [Text] -> PhoneticPlaceName
+ Data.Gedcom.Structure: PhoneticType :: Text -> PhoneticType
+ Data.Gedcom.Structure: PhysicalDescription :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Pinyin :: RomanType
+ Data.Gedcom.Structure: Place :: [Text] -> Maybe [Text] -> Maybe PhoneticPlaceName -> Maybe RomanPlaceName -> Maybe MapCoord -> [GDRef Note] -> Place
+ Data.Gedcom.Structure: Possessions :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Privacy :: RestrictionNotice
+ Data.Gedcom.Structure: Probate :: IndividualEventType
+ Data.Gedcom.Structure: Proven :: ChildLinkStatus
+ Data.Gedcom.Structure: QualityAssessment :: Word -> QualityAssessment
+ Data.Gedcom.Structure: RFN :: Text -> RFN
+ Data.Gedcom.Structure: RIN :: Text -> RIN
+ Data.Gedcom.Structure: Religion :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Repository :: Text -> Maybe Address -> [GDRef Note] -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> Repository
+ Data.Gedcom.Structure: RepositoryCitation :: Maybe (GDRef Repository) -> [GDRef Note] -> Maybe CallNumber -> RepositoryCitation
+ Data.Gedcom.Structure: Residence :: FamilyEventType
+ Data.Gedcom.Structure: ResidesAt :: IndividualAttributeType
+ Data.Gedcom.Structure: Retirement :: IndividualEventType
+ Data.Gedcom.Structure: Romaji :: RomanType
+ Data.Gedcom.Structure: RomanPlaceName :: RomanType -> [Text] -> RomanPlaceName
+ Data.Gedcom.Structure: RomanType :: Text -> RomanType
+ Data.Gedcom.Structure: RomanizedName :: Name -> RomanType -> PersonalNamePieces -> RomanizedName
+ Data.Gedcom.Structure: Sealing :: Pedigree
+ Data.Gedcom.Structure: SocialSecurity :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Source :: Maybe SourceData -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> [RepositoryCitation] -> [UserReference] -> Maybe RIN -> Maybe ChangeDate -> [GDRef Note] -> [GDRef Multimedia] -> Source
+ Data.Gedcom.Structure: SourceCitation :: Either SourceDescription (GDRef Source) -> Maybe Text -> [GDRef Multimedia] -> [GDRef Note] -> Maybe QualityAssessment -> SourceCitation
+ Data.Gedcom.Structure: SourceData :: [SourceRecordedEvent] -> Maybe Text -> [GDRef Note] -> SourceData
+ Data.Gedcom.Structure: SourceDescription :: Text -> [Text] -> SourceDescription
+ Data.Gedcom.Structure: SourceRecordedEvent :: [EventType] -> Maybe DatePeriod -> Maybe [Text] -> SourceRecordedEvent
+ Data.Gedcom.Structure: SpouseToFamilyLink :: GDRef Family -> [GDRef Note] -> SpouseToFamilyLink
+ Data.Gedcom.Structure: Submission :: Maybe (GDRef Submitter) -> Maybe Text -> Maybe Text -> Maybe Word -> Maybe Word -> Maybe Bool -> Maybe RIN -> [GDRef Note] -> Maybe ChangeDate -> Submission
+ Data.Gedcom.Structure: Submitter :: Name -> Maybe Address -> Maybe (GDRef Multimedia) -> [Language] -> Maybe RFN -> Maybe RIN -> [GDRef Note] -> Maybe ChangeDate -> Submitter
+ Data.Gedcom.Structure: Title :: Text -> IndividualAttributeType
+ Data.Gedcom.Structure: Undetermined :: Sex
+ Data.Gedcom.Structure: UserReference :: Text -> (Maybe Text) -> UserReference
+ Data.Gedcom.Structure: WadeGiles :: RomanType
+ Data.Gedcom.Structure: Wife :: Parent
+ Data.Gedcom.Structure: Will :: IndividualEventType
+ Data.Gedcom.Structure: Year :: Int -> Year
+ Data.Gedcom.Structure: [addressCity] :: Address -> Maybe Text
+ Data.Gedcom.Structure: [addressContact] :: Address -> ContactDetails
+ Data.Gedcom.Structure: [addressCountry] :: Address -> Maybe Text
+ Data.Gedcom.Structure: [addressEmail] :: ContactDetails -> [Text]
+ Data.Gedcom.Structure: [addressFax] :: ContactDetails -> [Text]
+ Data.Gedcom.Structure: [addressLines] :: Address -> Text
+ Data.Gedcom.Structure: [addressPhone] :: ContactDetails -> [Text]
+ Data.Gedcom.Structure: [addressPostcode] :: Address -> Maybe Text
+ Data.Gedcom.Structure: [addressState] :: Address -> Maybe Text
+ Data.Gedcom.Structure: [addressWWW] :: ContactDetails -> [Text]
+ Data.Gedcom.Structure: [associationCitation] :: Association -> [SourceCitation]
+ Data.Gedcom.Structure: [associationIndividual] :: Association -> GDRef Individual
+ Data.Gedcom.Structure: [associationNote] :: Association -> [GDRef Note]
+ Data.Gedcom.Structure: [associationRelation] :: Association -> Text
+ Data.Gedcom.Structure: [childLinkFamily] :: ChildToFamilyLink -> GDRef Family
+ Data.Gedcom.Structure: [childLinkNote] :: ChildToFamilyLink -> [GDRef Note]
+ Data.Gedcom.Structure: [childLinkPedigree] :: ChildToFamilyLink -> Maybe Pedigree
+ Data.Gedcom.Structure: [childLinkStatus] :: ChildToFamilyLink -> Maybe ChildLinkStatus
+ Data.Gedcom.Structure: [citeMultimedia] :: SourceCitation -> [GDRef Multimedia]
+ Data.Gedcom.Structure: [citeNote] :: SourceCitation -> [GDRef Note]
+ Data.Gedcom.Structure: [citePage] :: SourceCitation -> Maybe Text
+ Data.Gedcom.Structure: [citeQuality] :: SourceCitation -> Maybe QualityAssessment
+ Data.Gedcom.Structure: [citeSource] :: SourceCitation -> Either SourceDescription (GDRef Source)
+ Data.Gedcom.Structure: [corpAddress] :: Corp -> Maybe Address
+ Data.Gedcom.Structure: [corpName] :: Corp -> Text
+ Data.Gedcom.Structure: [eventDetailAddress] :: EventDetail -> Maybe Address
+ Data.Gedcom.Structure: [eventDetailAgency] :: EventDetail -> Maybe Text
+ Data.Gedcom.Structure: [eventDetailCause] :: EventDetail -> Maybe Text
+ Data.Gedcom.Structure: [eventDetailDate] :: EventDetail -> Maybe DateValue
+ Data.Gedcom.Structure: [eventDetailMultimedia] :: EventDetail -> [GDRef Multimedia]
+ Data.Gedcom.Structure: [eventDetailNote] :: EventDetail -> [GDRef Note]
+ Data.Gedcom.Structure: [eventDetailPlace] :: EventDetail -> Maybe Place
+ Data.Gedcom.Structure: [eventDetailReligion] :: EventDetail -> Maybe Text
+ Data.Gedcom.Structure: [eventDetailRestrictionNotice] :: EventDetail -> Maybe RestrictionNotice
+ Data.Gedcom.Structure: [eventDetailSourceCitation] :: EventDetail -> [SourceCitation]
+ Data.Gedcom.Structure: [eventDetailType] :: EventDetail -> Maybe Text
+ Data.Gedcom.Structure: [familyChangeDate] :: Family -> Maybe ChangeDate
+ Data.Gedcom.Structure: [familyChildren] :: Family -> [GDRef Individual]
+ Data.Gedcom.Structure: [familyEventDetailAgeHusband] :: FamilyEventDetail -> Maybe Word
+ Data.Gedcom.Structure: [familyEventDetailAgeWife] :: FamilyEventDetail -> Maybe Word
+ Data.Gedcom.Structure: [familyEventDetailDetail] :: FamilyEventDetail -> EventDetail
+ Data.Gedcom.Structure: [familyEventDetail] :: FamilyEvent -> FamilyEventDetail
+ Data.Gedcom.Structure: [familyEventType] :: FamilyEvent -> FamilyEventType
+ Data.Gedcom.Structure: [familyEvent] :: Family -> [FamilyEvent]
+ Data.Gedcom.Structure: [familyHusband] :: Family -> Maybe (GDRef Individual)
+ Data.Gedcom.Structure: [familyMultimedia] :: Family -> [GDRef Multimedia]
+ Data.Gedcom.Structure: [familyNote] :: Family -> [GDRef Note]
+ Data.Gedcom.Structure: [familyRIN] :: Family -> Maybe RIN
+ Data.Gedcom.Structure: [familyRestrictionNotice] :: Family -> Maybe RestrictionNotice
+ Data.Gedcom.Structure: [familySourceCitation] :: Family -> [SourceCitation]
+ Data.Gedcom.Structure: [familySubitter] :: Family -> [GDRef Submitter]
+ Data.Gedcom.Structure: [familyTotalChildren] :: Family -> Maybe Word
+ Data.Gedcom.Structure: [familyUserReference] :: Family -> [UserReference]
+ Data.Gedcom.Structure: [familyWife] :: Family -> Maybe (GDRef Individual)
+ Data.Gedcom.Structure: [gedcomFamily] :: Gedcom -> [GDRef Family]
+ Data.Gedcom.Structure: [gedcomForm] :: GedcomFormat -> GedcomForm
+ Data.Gedcom.Structure: [gedcomHeader] :: Gedcom -> Header
+ Data.Gedcom.Structure: [gedcomIndividual] :: Gedcom -> [GDRef Individual]
+ Data.Gedcom.Structure: [gedcomMultimedia] :: Gedcom -> [GDRef Multimedia]
+ Data.Gedcom.Structure: [gedcomNote] :: Gedcom -> [GDRef Note]
+ Data.Gedcom.Structure: [gedcomRepository] :: Gedcom -> [GDRef Repository]
+ Data.Gedcom.Structure: [gedcomSource] :: Gedcom -> [GDRef Source]
+ Data.Gedcom.Structure: [gedcomSubmitter] :: Gedcom -> [GDRef Submitter]
+ Data.Gedcom.Structure: [gedcomVersion] :: GedcomFormat -> Text
+ Data.Gedcom.Structure: [headerCharset] :: Header -> Charset
+ Data.Gedcom.Structure: [headerCopyright] :: Header -> Maybe Text
+ Data.Gedcom.Structure: [headerDate] :: Header -> Maybe UTCTime
+ Data.Gedcom.Structure: [headerDestination] :: Header -> Maybe Text
+ Data.Gedcom.Structure: [headerFile] :: Header -> Maybe FilePath
+ Data.Gedcom.Structure: [headerGedcomFormat] :: Header -> GedcomFormat
+ Data.Gedcom.Structure: [headerLang] :: Header -> Maybe Language
+ Data.Gedcom.Structure: [headerNote] :: Header -> Maybe Text
+ Data.Gedcom.Structure: [headerPlaceForm] :: Header -> Maybe [Text]
+ Data.Gedcom.Structure: [headerSourceCorp] :: HeaderSource -> Maybe Corp
+ Data.Gedcom.Structure: [headerSourceDataCopyright] :: HeaderSourceData -> Maybe Text
+ Data.Gedcom.Structure: [headerSourceDataDate] :: HeaderSourceData -> Maybe UTCTime
+ Data.Gedcom.Structure: [headerSourceDataName] :: HeaderSourceData -> Text
+ Data.Gedcom.Structure: [headerSourceData] :: HeaderSource -> Maybe HeaderSourceData
+ Data.Gedcom.Structure: [headerSourceName] :: HeaderSource -> Maybe Text
+ Data.Gedcom.Structure: [headerSourceSystemID] :: HeaderSource -> Text
+ Data.Gedcom.Structure: [headerSourceVersion] :: HeaderSource -> Maybe Text
+ Data.Gedcom.Structure: [headerSource] :: Header -> HeaderSource
+ Data.Gedcom.Structure: [headerSubmission] :: Header -> Maybe (GDRef Submission)
+ Data.Gedcom.Structure: [headerSubmitter] :: Header -> GDRef Submitter
+ Data.Gedcom.Structure: [individualAFN] :: Individual -> Maybe AFN
+ Data.Gedcom.Structure: [individualAlias] :: Individual -> [GDRef Individual]
+ Data.Gedcom.Structure: [individualAncestorInterest] :: Individual -> [GDRef Submitter]
+ Data.Gedcom.Structure: [individualAssociation] :: Individual -> [Association]
+ Data.Gedcom.Structure: [individualAttribute] :: Individual -> [IndividualAttribute]
+ Data.Gedcom.Structure: [individualChangeDate] :: Individual -> Maybe ChangeDate
+ Data.Gedcom.Structure: [individualChildToFamilyLink] :: Individual -> [ChildToFamilyLink]
+ Data.Gedcom.Structure: [individualDescendantInterest] :: Individual -> [GDRef Submitter]
+ Data.Gedcom.Structure: [individualEventDetailAge] :: IndividualEventDetail -> Maybe Word
+ Data.Gedcom.Structure: [individualEventDetailDetail] :: IndividualEventDetail -> EventDetail
+ Data.Gedcom.Structure: [individualEventDetail] :: IndividualEvent -> IndividualEventDetail
+ Data.Gedcom.Structure: [individualEventType] :: IndividualEvent -> IndividualEventType
+ Data.Gedcom.Structure: [individualEvent] :: Individual -> [IndividualEvent]
+ Data.Gedcom.Structure: [individualMultimedia] :: Individual -> [GDRef Multimedia]
+ Data.Gedcom.Structure: [individualName] :: Individual -> Maybe PersonalName
+ Data.Gedcom.Structure: [individualNote] :: Individual -> [GDRef Note]
+ Data.Gedcom.Structure: [individualRFN] :: Individual -> Maybe RFN
+ Data.Gedcom.Structure: [individualRIN] :: Individual -> Maybe RIN
+ Data.Gedcom.Structure: [individualRestrictionNotice] :: Individual -> Maybe RestrictionNotice
+ Data.Gedcom.Structure: [individualSex] :: Individual -> Maybe Sex
+ Data.Gedcom.Structure: [individualSourceCitation] :: Individual -> [SourceCitation]
+ Data.Gedcom.Structure: [individualSpouseToFamilyLink] :: Individual -> [SpouseToFamilyLink]
+ Data.Gedcom.Structure: [individualSubmitter] :: Individual -> [GDRef Submitter]
+ Data.Gedcom.Structure: [individualUserReference] :: Individual -> [UserReference]
+ Data.Gedcom.Structure: [multimediaChangeDate] :: Multimedia -> Maybe ChangeDate
+ Data.Gedcom.Structure: [multimediaFileFormat] :: MultimediaFile -> MultimediaFormat
+ Data.Gedcom.Structure: [multimediaFileLink] :: MultimediaFile -> Text
+ Data.Gedcom.Structure: [multimediaFile] :: Multimedia -> [MultimediaFile]
+ Data.Gedcom.Structure: [multimediaNote] :: Multimedia -> [GDRef Note]
+ Data.Gedcom.Structure: [multimediaRIN] :: Multimedia -> Maybe RIN
+ Data.Gedcom.Structure: [multimediaSourceCitation] :: Multimedia -> [SourceCitation]
+ Data.Gedcom.Structure: [multimediaTitl] :: Multimedia -> Maybe Text
+ Data.Gedcom.Structure: [multimediaTitle] :: MultimediaFile -> Maybe Text
+ Data.Gedcom.Structure: [multimediaUserReference] :: Multimedia -> [UserReference]
+ Data.Gedcom.Structure: [namePieceGiven] :: PersonalNamePieces -> [Text]
+ Data.Gedcom.Structure: [namePieceNameNote] :: PersonalNamePieces -> [GDRef Note]
+ Data.Gedcom.Structure: [namePieceNickname] :: PersonalNamePieces -> [Text]
+ Data.Gedcom.Structure: [namePiecePrefix] :: PersonalNamePieces -> [Text]
+ Data.Gedcom.Structure: [namePieceSuffix] :: PersonalNamePieces -> [Text]
+ Data.Gedcom.Structure: [namePieceSurnamePrefix] :: PersonalNamePieces -> [Text]
+ Data.Gedcom.Structure: [namePieceSurname] :: PersonalNamePieces -> [Text]
+ Data.Gedcom.Structure: [namePirceSourceCitation] :: PersonalNamePieces -> [SourceCitation]
+ Data.Gedcom.Structure: [noteChangeDate] :: Note -> Maybe ChangeDate
+ Data.Gedcom.Structure: [noteRIN] :: Note -> Maybe RIN
+ Data.Gedcom.Structure: [noteSourceCitation] :: Note -> [SourceCitation]
+ Data.Gedcom.Structure: [noteText] :: Note -> Text
+ Data.Gedcom.Structure: [noteUserReference] :: Note -> [UserReference]
+ Data.Gedcom.Structure: [personalNameName] :: PersonalName -> Name
+ Data.Gedcom.Structure: [personalNamePhonetic] :: PersonalName -> [PhoneticName]
+ Data.Gedcom.Structure: [personalNamePieces] :: PersonalName -> PersonalNamePieces
+ Data.Gedcom.Structure: [personalNameRoman] :: PersonalName -> [RomanizedName]
+ Data.Gedcom.Structure: [personalNameType] :: PersonalName -> Maybe NameType
+ Data.Gedcom.Structure: [phoneticName] :: PhoneticName -> Name
+ Data.Gedcom.Structure: [phoneticPieces] :: PhoneticName -> PersonalNamePieces
+ Data.Gedcom.Structure: [phoneticType] :: PhoneticName -> PhoneticType
+ Data.Gedcom.Structure: [placeForm] :: Place -> Maybe [Text]
+ Data.Gedcom.Structure: [placeMap] :: Place -> Maybe MapCoord
+ Data.Gedcom.Structure: [placeName] :: Place -> [Text]
+ Data.Gedcom.Structure: [placeNote] :: Place -> [GDRef Note]
+ Data.Gedcom.Structure: [placePhonetic] :: Place -> Maybe PhoneticPlaceName
+ Data.Gedcom.Structure: [placeRoman] :: Place -> Maybe RomanPlaceName
+ Data.Gedcom.Structure: [repoCiteCallNumber] :: RepositoryCitation -> Maybe CallNumber
+ Data.Gedcom.Structure: [repoCiteNote] :: RepositoryCitation -> [GDRef Note]
+ Data.Gedcom.Structure: [repoCiteRepository] :: RepositoryCitation -> Maybe (GDRef Repository)
+ Data.Gedcom.Structure: [repositoryAddress] :: Repository -> Maybe Address
+ Data.Gedcom.Structure: [repositoryChangeDate] :: Repository -> Maybe ChangeDate
+ Data.Gedcom.Structure: [repositoryName] :: Repository -> Text
+ Data.Gedcom.Structure: [repositoryNote] :: Repository -> [GDRef Note]
+ Data.Gedcom.Structure: [repositoryRIN] :: Repository -> Maybe RIN
+ Data.Gedcom.Structure: [repositoryUserReference] :: Repository -> [UserReference]
+ Data.Gedcom.Structure: [romanziedName] :: RomanizedName -> Name
+ Data.Gedcom.Structure: [romanziedPieces] :: RomanizedName -> PersonalNamePieces
+ Data.Gedcom.Structure: [romanziedType] :: RomanizedName -> RomanType
+ Data.Gedcom.Structure: [sourceAuthor] :: Source -> Maybe Text
+ Data.Gedcom.Structure: [sourceChangeDate] :: Source -> Maybe ChangeDate
+ Data.Gedcom.Structure: [sourceDataAgency] :: SourceData -> Maybe Text
+ Data.Gedcom.Structure: [sourceDataEventsRecorded] :: SourceData -> [SourceRecordedEvent]
+ Data.Gedcom.Structure: [sourceDataNote] :: SourceData -> [GDRef Note]
+ Data.Gedcom.Structure: [sourceData] :: Source -> Maybe SourceData
+ Data.Gedcom.Structure: [sourceMultimedia] :: Source -> [GDRef Multimedia]
+ Data.Gedcom.Structure: [sourceNote] :: Source -> [GDRef Note]
+ Data.Gedcom.Structure: [sourcePublicationFacts] :: Source -> Maybe Text
+ Data.Gedcom.Structure: [sourceRIN] :: Source -> Maybe RIN
+ Data.Gedcom.Structure: [sourceRecordedDate] :: SourceRecordedEvent -> Maybe DatePeriod
+ Data.Gedcom.Structure: [sourceRecordedEventType] :: SourceRecordedEvent -> [EventType]
+ Data.Gedcom.Structure: [sourceRecordedPlace] :: SourceRecordedEvent -> Maybe [Text]
+ Data.Gedcom.Structure: [sourceRepositoryCitations] :: Source -> [RepositoryCitation]
+ Data.Gedcom.Structure: [sourceShortTitle] :: Source -> Maybe Text
+ Data.Gedcom.Structure: [sourceText] :: Source -> Maybe Text
+ Data.Gedcom.Structure: [sourceTitle] :: Source -> Maybe Text
+ Data.Gedcom.Structure: [sourceUserReference] :: Source -> [UserReference]
+ Data.Gedcom.Structure: [spouseToFamilyLinkFamily] :: SpouseToFamilyLink -> GDRef Family
+ Data.Gedcom.Structure: [spouseToFamilyLinkNote] :: SpouseToFamilyLink -> [GDRef Note]
+ Data.Gedcom.Structure: [submissionAncestorGenerations] :: Submission -> Maybe Word
+ Data.Gedcom.Structure: [submissionChangeDate] :: Submission -> Maybe ChangeDate
+ Data.Gedcom.Structure: [submissionDescendentGenerations] :: Submission -> Maybe Word
+ Data.Gedcom.Structure: [submissionFamilyFile] :: Submission -> Maybe Text
+ Data.Gedcom.Structure: [submissionNote] :: Submission -> [GDRef Note]
+ Data.Gedcom.Structure: [submissionOrdinanceProcessing] :: Submission -> Maybe Bool
+ Data.Gedcom.Structure: [submissionRIN] :: Submission -> Maybe RIN
+ Data.Gedcom.Structure: [submissionSubmitter] :: Submission -> Maybe (GDRef Submitter)
+ Data.Gedcom.Structure: [submissionTempleCode] :: Submission -> Maybe Text
+ Data.Gedcom.Structure: [submitterAddress] :: Submitter -> Maybe Address
+ Data.Gedcom.Structure: [submitterChangeDate] :: Submitter -> Maybe ChangeDate
+ Data.Gedcom.Structure: [submitterLang] :: Submitter -> [Language]
+ Data.Gedcom.Structure: [submitterMedia] :: Submitter -> Maybe (GDRef Multimedia)
+ Data.Gedcom.Structure: [submitterName] :: Submitter -> Name
+ Data.Gedcom.Structure: [submitterNote] :: Submitter -> [GDRef Note]
+ Data.Gedcom.Structure: [submitterRFN] :: Submitter -> Maybe RFN
+ Data.Gedcom.Structure: [submitterRIN] :: Submitter -> Maybe RIN
+ Data.Gedcom.Structure: data Address
+ Data.Gedcom.Structure: data AdoptionDetail
+ Data.Gedcom.Structure: data Association
+ Data.Gedcom.Structure: data Calendar
+ Data.Gedcom.Structure: data CallNumber
+ Data.Gedcom.Structure: data ChangeDate
+ Data.Gedcom.Structure: data Charset
+ Data.Gedcom.Structure: data ChildLinkStatus
+ Data.Gedcom.Structure: data ChildToFamilyLink
+ Data.Gedcom.Structure: data ContactDetails
+ Data.Gedcom.Structure: data Corp
+ Data.Gedcom.Structure: data Date
+ Data.Gedcom.Structure: data DateApprox
+ Data.Gedcom.Structure: data DatePeriod
+ Data.Gedcom.Structure: data DateRange
+ Data.Gedcom.Structure: data DateValue
+ Data.Gedcom.Structure: data EventDetail
+ Data.Gedcom.Structure: data EventType
+ Data.Gedcom.Structure: data Family
+ Data.Gedcom.Structure: data FamilyEvent
+ Data.Gedcom.Structure: data FamilyEventDetail
+ Data.Gedcom.Structure: data FamilyEventType
+ Data.Gedcom.Structure: data Gedcom
+ Data.Gedcom.Structure: data GedcomForm
+ Data.Gedcom.Structure: data GedcomFormat
+ Data.Gedcom.Structure: data Header
+ Data.Gedcom.Structure: data HeaderSource
+ Data.Gedcom.Structure: data HeaderSourceData
+ Data.Gedcom.Structure: data Individual
+ Data.Gedcom.Structure: data IndividualAttribute
+ Data.Gedcom.Structure: data IndividualAttributeType
+ Data.Gedcom.Structure: data IndividualEvent
+ Data.Gedcom.Structure: data IndividualEventDetail
+ Data.Gedcom.Structure: data IndividualEventType
+ Data.Gedcom.Structure: data MapCoord
+ Data.Gedcom.Structure: data Multimedia
+ Data.Gedcom.Structure: data MultimediaFile
+ Data.Gedcom.Structure: data MultimediaFileFormat
+ Data.Gedcom.Structure: data MultimediaFormat
+ Data.Gedcom.Structure: data MultimediaType
+ Data.Gedcom.Structure: data Name
+ Data.Gedcom.Structure: data NameType
+ Data.Gedcom.Structure: data Note
+ Data.Gedcom.Structure: data Parent
+ Data.Gedcom.Structure: data Pedigree
+ Data.Gedcom.Structure: data PersonalName
+ Data.Gedcom.Structure: data PersonalNamePieces
+ Data.Gedcom.Structure: data PhoneticName
+ Data.Gedcom.Structure: data PhoneticPlaceName
+ Data.Gedcom.Structure: data PhoneticType
+ Data.Gedcom.Structure: data Place
+ Data.Gedcom.Structure: data Repository
+ Data.Gedcom.Structure: data RepositoryCitation
+ Data.Gedcom.Structure: data RestrictionNotice
+ Data.Gedcom.Structure: data RomanPlaceName
+ Data.Gedcom.Structure: data RomanType
+ Data.Gedcom.Structure: data RomanizedName
+ Data.Gedcom.Structure: data Sex
+ Data.Gedcom.Structure: data Source
+ Data.Gedcom.Structure: data SourceCitation
+ Data.Gedcom.Structure: data SourceData
+ Data.Gedcom.Structure: data SourceDescription
+ Data.Gedcom.Structure: data SourceRecordedEvent
+ Data.Gedcom.Structure: data SpouseToFamilyLink
+ Data.Gedcom.Structure: data Submission
+ Data.Gedcom.Structure: data Submitter
+ Data.Gedcom.Structure: data UserReference
+ Data.Gedcom.Structure: instance GHC.Classes.Eq Data.Gedcom.Structure.GedcomForm
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.AFN
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Address
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.AdoptionDetail
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Association
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Calendar
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.CallNumber
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.ChangeDate
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Charset
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.ChildLinkStatus
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.ChildToFamilyLink
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.ContactDetails
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Corp
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Date
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.DateApprox
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.DatePeriod
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.DateRange
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.DateValue
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.EventDetail
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.EventType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Family
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.FamilyEvent
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.FamilyEventDetail
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.FamilyEventType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Gedcom
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.GedcomForm
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.GedcomFormat
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Header
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.HeaderSource
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.HeaderSourceData
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Individual
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.IndividualAttribute
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.IndividualAttributeType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.IndividualEvent
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.IndividualEventDetail
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.IndividualEventType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Language
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Latitude
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Longitude
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.MapCoord
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Multimedia
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.MultimediaFile
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.MultimediaFileFormat
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.MultimediaFormat
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.MultimediaType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Name
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.NameType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Note
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Parent
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Pedigree
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.PersonalName
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.PersonalNamePieces
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.PhoneticName
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.PhoneticPlaceName
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.PhoneticType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Place
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.QualityAssessment
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RFN
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RIN
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Repository
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RepositoryCitation
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RestrictionNotice
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RomanPlaceName
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RomanType
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.RomanizedName
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Sex
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Source
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.SourceCitation
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.SourceData
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.SourceDescription
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.SourceRecordedEvent
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.SpouseToFamilyLink
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Submission
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Submitter
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.UserReference
+ Data.Gedcom.Structure: instance GHC.Show.Show Data.Gedcom.Structure.Year
+ Data.Gedcom.Structure: newtype AFN
+ Data.Gedcom.Structure: newtype Language
+ Data.Gedcom.Structure: newtype Latitude
+ Data.Gedcom.Structure: newtype Longitude
+ Data.Gedcom.Structure: newtype QualityAssessment
+ Data.Gedcom.Structure: newtype RFN
+ Data.Gedcom.Structure: newtype RIN
+ Data.Gedcom.Structure: newtype Year
Files
- changelog.md +5/−0
- gedcom.cabal +16/−13
- src/Data/Gedcom.hs +5/−4
- src/Data/Gedcom/Common.hs +0/−131
- src/Data/Gedcom/Internal/Common.hs +5/−1
- src/Data/Gedcom/Internal/CoreTypes.hs +131/−0
- src/Data/Gedcom/Internal/LineParser.hs +148/−0
- src/Data/Gedcom/Internal/ParseMonads.hs +120/−0
- src/Data/Gedcom/Internal/Parser.hs +1135/−0
- src/Data/Gedcom/LineParser.hs +0/−147
- src/Data/Gedcom/ParseMonads.hs +0/−120
- src/Data/Gedcom/Parser.hs +0/−1123
- src/Data/Gedcom/Structure.hs +1/−1
- test/Spec.hs +152/−1
changelog.md view
@@ -1,3 +1,8 @@+0.2.0.0+ * Upgrade to stackage 9.6 and make ready for GHC 8.2+ * Add some test cases+ * Expose internal modules+ 0.1.0.0 * Initial release
gedcom.cabal view
@@ -1,15 +1,14 @@ name: gedcom-version: 0.1.0.0+version: 0.2.0.0 synopsis: Parser for the GEDCOM genealogy file format. description: A parser for the legacy GEDCOM 5.5 file format. GEDCOM is- widely used by genealogy software, despite the limitations- of the format.+ a widely used file format in genealogy. homepage: https://github.com/CLowcay/hs-gedcom license: BSD3 license-file: LICENSE author: Callum Lowcay maintainer: cwslowcay@gmail.com-copyright: 2017 Callum Lowcay+copyright: 2018 Callum Lowcay category: Genealogy build-type: Simple extra-source-files: README.md changelog.md@@ -19,22 +18,23 @@ hs-source-dirs: src ghc-options: -Wall exposed-modules: Data.Gedcom- , Data.Text.Encoding.ANSEL- other-modules: Data.Gedcom.Common , Data.Gedcom.Internal.Common- , Data.Gedcom.LineParser- , Data.Gedcom.ParseMonads- , Data.Gedcom.Parser+ , Data.Gedcom.Internal.CoreTypes+ , Data.Gedcom.Internal.LineParser+ , Data.Gedcom.Internal.ParseMonads+ , Data.Gedcom.Internal.Parser , Data.Gedcom.Structure- build-depends: base >= 4.7 && < 5+ , Data.Text.Encoding.ANSEL+ other-modules: + build-depends: base >= 4.8 && < 5 , array >= 0.5.1.1 && < 0.6 , bytestring >= 0.10.8.1 && < 0.11 , containers >= 0.5.7.1 && < 0.6- , megaparsec >= 5.3.1 && < 5.4- , monad-loops >= 0.4.3 && < 4.4+ , megaparsec >= 6.3 && < 6.4+ , monad-loops >= 0.4.3 && < 0.5 , mtl >= 2.2.1 && < 2.3 , text-all >= 0.4.1.1 && < 0.5- , time >= 1.6.0.1 && < 1.7+ , time >= 1.8 && < 1.9 default-language: Haskell2010 test-suite gedcom-test@@ -43,6 +43,9 @@ main-is: Spec.hs build-depends: base , gedcom+ , hspec >= 2.4.4 && < 2.5+ , text-all >= 0.4.1.1 && < 0.5+ , megaparsec >= 5.3.1 && < 5.4 ghc-options: -threaded -rtsopts -with-rtsopts=-N default-language: Haskell2010
src/Data/Gedcom.hs view
@@ -24,14 +24,15 @@ import Control.Applicative import Data.Dynamic import Data.Either-import Data.Gedcom.Common-import Data.Gedcom.LineParser-import Data.Gedcom.ParseMonads-import Data.Gedcom.Parser+import Data.Gedcom.Internal.CoreTypes+import Data.Gedcom.Internal.LineParser+import Data.Gedcom.Internal.ParseMonads+import Data.Gedcom.Internal.Parser import Data.Gedcom.Structure import Data.Maybe import Data.Monoid import Data.Text.Encoding.ANSEL+import Data.Typeable import qualified Data.ByteString as B import qualified Data.Map as M import qualified Data.Text.All as T
− src/Data/Gedcom/Common.hs
@@ -1,131 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}--{-|-Module: Data.Gedcom.Common-Description: Common utility functions for parsing GEDCOM-Copyright: (c) Callum Lowcay, 2017-License: BSD3-Maintainer: cwslowcay@gmail.com-Stability: experimental-Portability: GHC--}-module Data.Gedcom.Common (- GDRefError (..),- GDError (..),- GDRef (..),- GDRoot (..),- GDTree (..),- GDLine (..),- GDLineValue (..),- GDLineItem (..),- GDEscape (..),- GDXRefID (..),- GDTag (..),- GDLevel (..),-- gdLineData,- gdTrimLineItem,- gdIgnoreEscapes,- gdFilterEscapes-) where--import Control.Arrow-import Data.Char-import Data.List-import Data.Monoid-import Data.Typeable-import qualified Data.Text.All as T---- | An error arising from dereferencing a 'GDRef'-data GDRefError =- RefNotPresent GDXRefID -- ^ The referred structure doesn't exist.- | WrongRefType TypeRep TypeRep -- ^ Dereferenced structure had the wrong type--instance Show GDRefError where- show (RefNotPresent thisID) = "Missing referenced structure " ++ (show thisID)- show (WrongRefType got expected) = "Referenced value has wrong type, expected "- ++ (show expected) ++ " but saw " ++ (show got)---- | A parse error.-data GDError =- LineFormatError T.Text -- ^ A badly formatted GEDCOM line- | UnexpectedRef T.Text -- ^ A reference where a reference wasn't allowed- | RequiredRef T.Text -- ^ Missing a reference where a reference was required- | DuplicateRef T.Text -- ^ Two targets for the same reference- | FormatError T.Text -- ^ A badly formatted field- | TagError T.Text -- ^ The wrong tag- deriving Show---- | A reference to another structure-data GDRef a =- GDStructure a -- ^ Already dereferenced.- | GDXRef GDXRefID -- ^ The 'GDXRefID' to look up- deriving Show---- | A raw GEDCOM syntax tree-data GDRoot = GDRoot [GDTree] deriving Show---- | A GEDCOM subtree-data GDTree = GDTree GDLine [GDTree] deriving Show---- | A GEDCOM line-data GDLine = GDLine GDLevel (Maybe GDXRefID) GDTag (Maybe GDLineValue)- deriving Show---- | The value field-data GDLineValue =- GDLineItemV GDLineItem | GDXRefIDV GDXRefID deriving (Show, Eq)---- | Line text-newtype GDLineItem = GDLineItem [(Maybe GDEscape, T.Text)] deriving (Show, Eq)---- | An escape sequence-newtype GDEscape = GDEscape T.Text deriving (Show, Eq)---- | A cross reference ID-newtype GDXRefID = GDXRefID T.Text deriving (Show, Eq, Ord)---- | The tag field-newtype GDTag = GDTag T.Text deriving (Show, Eq, Ord)---- | The level field-newtype GDLevel = GDLevel Int deriving (Show, Eq, Ord, Num)---- | Extract the line text-gdLineData :: GDLineItem -> [(Maybe GDEscape, T.Text)]-gdLineData (GDLineItem v) = v--instance Monoid GDLineItem where- mempty = GDLineItem []- mappend (GDLineItem l1) (GDLineItem l2) =- GDLineItem . fmap coalease . groupBy canCoalease$ l1 <> l2- where- coalease [] = (Nothing, "") - coalease (l:ls) = foldl' (\(_, t1) (e, t2) -> (e, t1 <> t2)) l ls- canCoalease (Nothing, _) (_, _) = True- canCoalease _ _ = False---- | Trim white space off the start an end of a GEDCOM line text.-gdTrimLineItem :: GDLineItem -> GDLineItem-gdTrimLineItem (GDLineItem []) = GDLineItem []-gdTrimLineItem (GDLineItem ((e, t):rst)) =- let- rst' = reverse$ case reverse rst of- [] -> []- ((e', t'):rst'') -> (e', T.dropWhile isSpace t'):rst''- in GDLineItem$ (e, T.dropWhile isSpace t):rst'---- | Ignore escape sequences-gdIgnoreEscapes :: [(Maybe GDEscape, T.Text)] -> T.Text-gdIgnoreEscapes = T.concat . fmap snd---- | Ignore certain escape sequences-gdFilterEscapes ::- [GDEscape] -> [(Maybe GDEscape, T.Text)] -> [(Maybe GDEscape, T.Text)]-gdFilterEscapes escapes =- gdLineData . mconcat . fmap GDLineItem . fmap (:[]) . fmap (first f)- where- f (Just e) = if e `elem` escapes then Just e else Nothing- f Nothing = Nothing-
src/Data/Gedcom/Internal/Common.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ {-| Module: Data.Gedcom.Internal.Common Description: Common utility functions for parsing@@ -17,11 +19,13 @@ import Data.Char import Data.Maybe import Data.Time.Clock+import Data.Void import qualified Data.Text.All as T import Text.Megaparsec+import Text.Megaparsec.Char -- | Parsers from 'T.Text' using the default error component.-type Parser = Parsec Dec T.Text+type Parser = Parsec Void T.Text infixl 1 <&>
+ src/Data/Gedcom/Internal/CoreTypes.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module: Data.Gedcom.Common+Description: Common utility functions for parsing GEDCOM+Copyright: (c) Callum Lowcay, 2017+License: BSD3+Maintainer: cwslowcay@gmail.com+Stability: experimental+Portability: GHC+-}+module Data.Gedcom.Internal.CoreTypes (+ GDRefError (..),+ GDError (..),+ GDRef (..),+ GDRoot (..),+ GDTree (..),+ GDLine (..),+ GDLineValue (..),+ GDLineItem (..),+ GDEscape (..),+ GDXRefID (..),+ GDTag (..),+ GDLevel (..),++ gdLineData,+ gdTrimLineItem,+ gdIgnoreEscapes,+ gdFilterEscapes+) where++import Control.Arrow+import Data.Char+import Data.List+import Data.Monoid+import Data.Typeable+import qualified Data.Text.All as T++-- | An error arising from dereferencing a 'GDRef'+data GDRefError =+ RefNotPresent GDXRefID -- ^ The referred structure doesn't exist.+ | WrongRefType TypeRep TypeRep -- ^ Dereferenced structure had the wrong type++instance Show GDRefError where+ show (RefNotPresent thisID) = "Missing referenced structure " ++ (show thisID)+ show (WrongRefType got expected) = "Referenced value has wrong type, expected "+ ++ (show expected) ++ " but saw " ++ (show got)++-- | A parse error.+data GDError =+ LineFormatError T.Text -- ^ A badly formatted GEDCOM line+ | UnexpectedRef T.Text -- ^ A reference where a reference wasn't allowed+ | RequiredRef T.Text -- ^ Missing a reference where a reference was required+ | DuplicateRef T.Text -- ^ Two targets for the same reference+ | FormatError T.Text -- ^ A badly formatted field+ | TagError T.Text -- ^ The wrong tag+ deriving Show++-- | A reference to another structure+data GDRef a =+ GDStructure a -- ^ Already dereferenced.+ | GDXRef GDXRefID -- ^ The 'GDXRefID' to look up+ deriving (Show, Eq)++-- | A raw GEDCOM syntax tree+data GDRoot = GDRoot [GDTree] deriving (Show, Eq)++-- | A GEDCOM subtree+data GDTree = GDTree GDLine [GDTree] deriving (Show, Eq)++-- | A GEDCOM line+data GDLine = GDLine GDLevel (Maybe GDXRefID) GDTag (Maybe GDLineValue)+ deriving (Show, Eq)++-- | The value field+data GDLineValue =+ GDLineItemV GDLineItem | GDXRefIDV GDXRefID deriving (Show, Eq)++-- | Line text+newtype GDLineItem = GDLineItem [(Maybe GDEscape, T.Text)] deriving (Show, Eq)++-- | An escape sequence+newtype GDEscape = GDEscape T.Text deriving (Show, Eq)++-- | A cross reference ID+newtype GDXRefID = GDXRefID T.Text deriving (Show, Eq, Ord)++-- | The tag field+newtype GDTag = GDTag T.Text deriving (Show, Eq, Ord)++-- | The level field+newtype GDLevel = GDLevel Int deriving (Show, Eq, Ord, Num)++-- | Extract the line text+gdLineData :: GDLineItem -> [(Maybe GDEscape, T.Text)]+gdLineData (GDLineItem v) = v++instance Monoid GDLineItem where+ mempty = GDLineItem []+ mappend (GDLineItem l1) (GDLineItem l2) =+ GDLineItem . fmap coalease . groupBy canCoalease$ l1 <> l2+ where+ coalease [] = (Nothing, "") + coalease (l:ls) = foldl' (\(_, t1) (e, t2) -> (e, t1 <> t2)) l ls+ canCoalease (Nothing, _) (_, _) = True+ canCoalease _ _ = False++-- | Trim white space off the start an end of a GEDCOM line text.+gdTrimLineItem :: GDLineItem -> GDLineItem+gdTrimLineItem (GDLineItem []) = GDLineItem []+gdTrimLineItem (GDLineItem ((e, t):rst)) =+ let+ rst' = reverse$ case reverse rst of+ [] -> []+ ((e', t'):rst'') -> (e', T.dropWhile isSpace t'):rst''+ in GDLineItem$ (e, T.dropWhile isSpace t):rst'++-- | Ignore escape sequences+gdIgnoreEscapes :: [(Maybe GDEscape, T.Text)] -> T.Text+gdIgnoreEscapes = T.concat . fmap snd++-- | Ignore certain escape sequences+gdFilterEscapes ::+ [GDEscape] -> [(Maybe GDEscape, T.Text)] -> [(Maybe GDEscape, T.Text)]+gdFilterEscapes escapes =+ gdLineData . mconcat . fmap GDLineItem . fmap (:[]) . fmap (first f)+ where+ f (Just e) = if e `elem` escapes then Just e else Nothing+ f Nothing = Nothing+
+ src/Data/Gedcom/Internal/LineParser.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}++{-|+Module: Data.Gedcom.LineParser+Description: Low-level GEDCOM parser+Copyright: (c) Callum Lowcay, 2017+License: BSD3+Maintainer: cwslowcay@gmail.com+Stability: experimental+Portability: GHC++This module parses a Text string into a GEDCOM syntax tree.++-}+module Data.Gedcom.Internal.LineParser (+ gdRoot, gdDelim+) where++import Control.Monad+import Data.Char+import Data.Gedcom.Internal.Common+import Data.Gedcom.Internal.CoreTypes+import Data.Maybe+import Data.Monoid+import qualified Data.Text.All as T+import Text.Megaparsec+import Text.Megaparsec.Char++-- | Parse any_char.+gdAnyChar :: Parser T.Text+gdAnyChar = (fmap T.singleton gdNonAt) <|> "@@"++-- | Parse non_at.+gdNonAt :: Parser Char+gdNonAt = satisfy (\c -> (not.isControl) c && c /= '@' && c /= '\x7F')++-- | Parse alphanum.+gdAlphaNum :: Parser Char+gdAlphaNum = alphaNumChar <|> char '_'++-- | Parse delim.+gdDelim :: Parser (Maybe Char)+gdDelim = optional$ char '\x20'++-- | Parse escape.+gdEscape :: Parser GDEscape+gdEscape = GDEscape <$>+ ("@#" *> gdEscapeText <* char '@' <* (optional$ char ' '))++-- | Parse escape_text.+gdEscapeText :: Parser T.Text+gdEscapeText = T.concat <$> many gdAnyChar++-- | Parse level.+gdLevel :: Parser GDLevel+gdLevel = GDLevel . read <$> count' 1 2 digitChar <* gdDelim++-- | Parse line_item.+gdLineItem :: Parser GDLineItem+gdLineItem = fmap GDLineItem . some$+ (,) <$> optional gdEscape <*> (T.concat <$> some gdAnyChar)++-- | Parse pointer.+gdPointer :: Parser GDXRefID+gdPointer = char '@' *> plabel <* char '@'+ where plabel = fmap (GDXRefID . T.pack)$+ (:) <$> gdAlphaNum <*> (many gdNonAt)++-- | Parse line_value+gdLineValue :: Parser GDLineValue+gdLineValue = eitherP gdPointer gdLineItem <&> \x -> case x of+ Left v -> GDXRefIDV v+ Right v -> GDLineItemV v++-- | Parse optional_line_value.+gdOptionalLineValue :: Parser GDLineValue+gdOptionalLineValue = gdDelim *> gdLineValue++-- | Parse optional_xref_ID.+gdOptionalXRefID :: Parser (Maybe GDXRefID)+gdOptionalXRefID = gdXRefID <* gdDelim++-- | Parse tag.+gdTag :: Parser GDTag+gdTag = GDTag . T.toUpper . T.pack <$> many gdAlphaNum++-- | parse terminator.+gdTerminator :: Parser T.Text+gdTerminator = "\n" <|> "\r" <|> "\r\n" <|> "\n\r"++-- | Parse xref_ID.+gdXRefID :: Parser (Maybe GDXRefID)+gdXRefID = optional $ fmap (\(GDXRefID t) -> GDXRefID t) gdPointer++-- | Parse gedcom_line.+gdLine :: Parser GDLine+gdLine = GDLine <$>+ gdLevel <*>+ gdOptionalXRefID <*>+ gdTag <*>+ (optional gdOptionalLineValue) <* gdTerminator++-- | Convert local ids to global ids.+gdExpandID ::+ GDXRefID -- ^ The parent structure's ID+ -> GDXRefID -- ^ The local ID.+ -> GDXRefID -- ^ A global ID.+gdExpandID (GDXRefID pid) s@(GDXRefID sub) =+ case T.uncons sub of+ Nothing -> s+ Just ('!', _) -> GDXRefID$ pid <> sub+ _ -> s++-- | Convert local ids to global ids.+gdExpandPointer ::+ GDXRefID -- ^ The parent structure's ID.+ -> GDLineValue -- ^ The line to update.+ -> GDLineValue -- ^ An updated line where local ID's have been made global.+gdExpandPointer pid v = case v of+ GDLineItemV _ -> v+ GDXRefIDV p -> GDXRefIDV$ gdExpandID pid p++-- | Parse a line at a fixed level+gdLineLevel ::+ GDXRefID -- ^ The parent ID + -> GDLevel -- ^ The level to parse the line at+ -> Parser GDLine+gdLineLevel pid n = do+ (GDLine n' xrid tag v) <- gdLine+ when (n' /= n)$ fail$ "Saw a " ++ (show tag) +++ " tag at level " ++ (show n') +++ " but expected level was " ++ (show n)+ return$ GDLine n' (fmap (gdExpandID pid) xrid) tag (fmap (gdExpandPointer pid) v)++-- | Parse a GEDCOM subtree+gdTree ::+ GDXRefID -- ^ The parent ID+ -> GDLevel -- ^ The level where the subtree is rooted+ -> Parser GDTree+gdTree pid n = try$ do+ line@(GDLine _ pid' _ _) <- gdLineLevel pid n+ GDTree line <$> many (gdTree (fromMaybe pid pid') (n + 1))++-- | Parse the raw GEDCOM syntax tree.+gdRoot :: Parser GDRoot+gdRoot = GDRoot <$> (many$ gdTree (GDXRefID "") 0)+
+ src/Data/Gedcom/Internal/ParseMonads.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module: Data.Gedcom.ParseMonads+Description: Monads for parsing GEDCOM records+Copyright: (c) Callum Lowcay, 2017+License: BSD3+Maintainer: cwslowcay@gmail.com+Stability: experimental+Portability: GHC++This module contains monads and utility functions for extracting GEDCOM records+from the raw syntax tree.++-}+module Data.Gedcom.Internal.ParseMonads (+ StructureParser,+ MultiMonad,+ runMultiMonad,+ parseMulti,+ parseOptional,+ parseRequired,+ StructureMonad,+ addReference,+ runStructure+) where++import Control.Monad+import Control.Monad.Except+import Control.Monad.State+import Data.Dynamic+import Data.Either+import Data.Foldable+import Data.Gedcom.Internal.CoreTypes+import Data.Maybe+import Data.Monoid+import qualified Data.Map as M+import qualified Data.Text.All as T++-- | A parser that extracts a GEDCOM structure from a GEDCOM subtree.+type StructureParser a =+ GDTree -- ^ The subtree to parse.+ -> StructureMonad (Either GDTree a) -- ^ Either parsed structure, or the subtree itself if the subtree doesn't contain the expected GEDCOM structure.++-- | A Monad for parsing GEDCOM structures out of a list of GEDCOM subtrees.+newtype MultiMonad a =+ MultiMonad (ExceptT GDError (StateT [GDTree] StructureMonad) a)+ deriving (Monad, Functor, Applicative, MonadError GDError)++-- | Run a 'MultiMonad' into a 'StructureMonad'.+runMultiMonad ::+ [GDTree] -- ^ The subtrees to parse the structure from.+ -> MultiMonad a -- ^ The MultiMonad that does the parsing.+ -> StructureMonad a+runMultiMonad children (MultiMonad m) =+ ((flip evalStateT) children.runExceptT$ m) >>= rethrowError+ where rethrowError x = case x of+ Left e -> throwError e+ Right v -> return v++-- | Parse multiple instances of a structure+parseMulti :: StructureParser a -> MultiMonad [a]+parseMulti p = MultiMonad$ do+ ls <- lift$ get+ (others, vs) <- lift$ lift$ partitionEithers <$> p `traverse` ls+ lift$ put others+ return vs++-- | Parse an optional instance of a structure+parseOptional :: StructureParser a -> MultiMonad (Maybe a)+parseOptional p = MultiMonad$ do+ ls <- lift$ get+ (mr, leftover) <-+ lift$ lift$ foldrM (\v (r, rest) ->+ if isJust r then return (r, v:rest)+ else pick v rest.toMaybe <$> p v) (Nothing, []) ls+ lift$ put leftover+ return mr+ where+ toMaybe (Left _) = Nothing+ toMaybe (Right v) = Just v+ pick v rest Nothing = (Nothing, v:rest)+ pick _ rest x = (x, rest)++-- | Parse a required instance of a structure+parseRequired ::+ GDTag -- ^ The tag that identifies the required structure.+ -> StructureParser a+ -> MultiMonad a+parseRequired tag p = do+ r <- parseOptional p+ case r of+ Just v -> return v+ Nothing -> throwError.TagError$+ "Could not find required " <> (T.show tag) <> " tag"++-- | A monad for parsing an instance of a GEDCOM structure from a GEDCOM+-- subtree.+newtype StructureMonad a =+ StructureMonad (ExceptT GDError (State (M.Map GDXRefID Dynamic)) a)+ deriving (Monad, Functor, Applicative, MonadError GDError)++-- | Add a reference to the cross reference table.+addReference :: Typeable a+ => GDXRefID -- ^ The cross reference to add.+ -> a -- ^ The value the reference will resolve to.+ -> StructureMonad ()+addReference thisID value = StructureMonad$ do+ alreadySeen <- M.member thisID <$> lift get+ when alreadySeen$+ throwError.DuplicateRef$ "Duplicate definition of " <> (T.show thisID)+ lift.modify$ M.insert thisID (toDyn value)+ return ()++-- | Run a 'StructureMonad', returning either an error or a value, and the+-- cross reference table.+runStructure :: StructureMonad a -> (Either GDError a, M.Map GDXRefID Dynamic)+runStructure (StructureMonad m) = (flip runState) M.empty . runExceptT$ m+
+ src/Data/Gedcom/Internal/Parser.hs view
@@ -0,0 +1,1135 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecursiveDo #-}+{-# LANGUAGE TupleSections #-}++{-|+Module: Data.Gedcom.Parser+Description: GEDCOM high level parsers+Copyright: (c) Callum Lowcay, 2017+License: BSD3+Maintainer: cwslowcay@gmail.com+Stability: experimental+Portability: GHC++These parsers extract the GEDCOM records from the raw syntax tree.++-}+module Data.Gedcom.Internal.Parser (+ parseGedcom,+ parseHeader,++ parseBoolTag,+ parseWordTag,+ parseTextTag,+ parseListTag,+ parseTag,+ parseLinkTag,+ parseNoLinkTag+) where++import Control.Applicative+import Control.Monad.Except+import Data.Bifunctor+import Data.Dynamic+import Data.Gedcom.Internal.Common+import Data.Gedcom.Internal.CoreTypes+import Data.Gedcom.Internal.LineParser+import Data.Gedcom.Internal.ParseMonads+import Data.Gedcom.Structure+import Data.Maybe+import Data.Monoid+import Data.Time.Calendar+import Data.Time.Clock+import qualified Data.Map.Lazy as M+import qualified Data.Text.All as T+import Text.Megaparsec+import Text.Megaparsec.Char++-- | Parse a 'Gedcom' value from the raw GEDCOM syntax tree.+parseGedcom :: GDRoot -> (Either GDError Gedcom, M.Map GDXRefID Dynamic)+parseGedcom (GDRoot children) =+ runStructure.runMultiMonad children$ Gedcom+ <$> parseRequired (GDTag "HEAD") parseHeader+ <*> parseMulti parseFamily+ <*> parseMulti (parseIndividual (GDTag "INDI"))+ <*> parseMulti parseMultimediaRecord+ <*> parseMulti parseNote+ <*> parseMulti parseRepository+ <*> parseMulti parseSource+ <*> parseMulti (parseSubmitter (GDTag "SUBM"))++-- | Parse a 'Header'.+parseHeader :: StructureParser Header+parseHeader = parseNoLinkTag (GDTag "HEAD")$ \(_, children) ->+ runMultiMonad children$ Header+ <$> parseRequired (GDTag "SOUR") parseHeaderSource+ <*> parseOptional (parseTextTag (GDTag "DEST"))+ <*> parseOptional parseExactDateTime+ <*> parseRequired (GDTag "SUBM") (parseSubmitter (GDTag "SUBM"))+ <*> parseOptional parseSubmission+ <*> parseOptional parseFile+ <*> parseOptional parseCopyright+ <*> parseRequired (GDTag "GEDC") parseGedcomFormat+ <*> parseRequired (GDTag "CHAR") parseCharset+ <*> parseOptional parseLanguage+ <*> parseOptional parsePlaceForm+ <*> parseOptional (parseTextTag (GDTag "NOTE"))++-- | Parse a 'HeaderSource'.+parseHeaderSource :: StructureParser HeaderSource+parseHeaderSource = parseNoLinkTag (GDTag "SOUR")$ \(sid, children) ->+ runMultiMonad children$ HeaderSource (gdIgnoreEscapes sid)+ <$> parseOptional parseVersion+ <*> parseOptional parseName+ <*> parseOptional parseCorp+ <*> parseOptional parseHeaderSourceData++-- | Parse a 'Corp'.+parseCorp :: StructureParser Corp+parseCorp = parseNoLinkTag (GDTag "COPR")$ \(name, children) ->+ runMultiMonad children$ Corp (gdIgnoreEscapes name)+ <$> (parseContactDetails >>= (parseOptional.parseAddress))++-- | Parse a 'HeaderSourceData'.+parseHeaderSourceData :: StructureParser HeaderSourceData+parseHeaderSourceData = parseNoLinkTag (GDTag "DATA")$ \(name, children) ->+ runMultiMonad children$ HeaderSourceData (gdIgnoreEscapes name)+ <$> parseOptional parseExactDate+ <*> parseOptional parseCopyright++-- | Parse a 'Family'.+parseFamily :: StructureParser (GDRef Family)+parseFamily = parseTag (GDTag "FAM")$ \(_, children) ->+ runMultiMonad children$ Family+ <$> parseOptional parseRestrictionNotice+ <*> parseFamilyEvent+ <*> parseOptional (parseIndividual (GDTag "HUSB"))+ <*> parseOptional (parseIndividual (GDTag "WIFE"))+ <*> parseMulti (parseIndividual (GDTag "CHIL"))+ <*> parseOptional (parseWordTag (GDTag "NCHI"))+ <*> parseMulti (parseSubmitter (GDTag "SUBM"))+ <*> parseMulti parseUserReference+ <*> parseOptional parseRIN+ <*> parseOptional parseChangeDate+ <*> parseMulti parseNote+ <*> parseMulti parseSourceCitation+ <*> parseMulti parseMultimedia++-- | Parse an 'Individual'.+parseIndividual :: GDTag -> StructureParser (GDRef Individual)+parseIndividual tag = parseTag tag$ \(_, children) ->+ runMultiMonad children$ Individual+ <$> parseOptional parseRestrictionNotice+ <*> parseOptional parsePersonalName+ <*> parseOptional parseSex+ <*> parseIndividualEvent+ <*> parseIndividualAttribute+ <*> parseMulti parseChildToFamilyLink+ <*> parseMulti parseSpouseToFamilyLink+ <*> parseMulti (parseSubmitter (GDTag "SUBM"))+ <*> parseMulti parseAssociation+ <*> parseMulti (parseIndividual (GDTag "ALIA"))+ <*> parseMulti (parseSubmitter (GDTag "ANCI"))+ <*> parseMulti (parseSubmitter (GDTag "DECI"))+ <*> parseOptional parseRFN+ <*> parseOptional parseAFN+ <*> parseMulti parseUserReference+ <*> parseOptional parseRIN+ <*> parseOptional parseChangeDate+ <*> parseMulti parseNote+ <*> parseMulti parseSourceCitation+ <*> parseMulti parseMultimedia++-- | Parse a 'Node'.+parseNote :: StructureParser (GDRef Note)+parseNote = parseTag (GDTag "NOTE")$ \(t, children) ->+ runMultiMonad children$ Note (gdIgnoreEscapes t)+ <$> parseMulti parseUserReference+ <*> parseOptional parseRIN+ <*> parseMulti parseSourceCitation+ <*> parseOptional parseChangeDate++-- | Parse a 'Repository'.+parseRepository :: StructureParser (GDRef Repository)+parseRepository = parseTag (GDTag "REPO")$ \(_, children) ->+ runMultiMonad children$ Repository+ <$> parseRequired (GDTag "NAME") parseName+ <*> (parseContactDetails >>= (parseOptional.parseAddress))+ <*> parseMulti parseNote+ <*> parseMulti parseUserReference+ <*> parseOptional parseRIN+ <*> parseOptional parseChangeDate++-- | Parse a 'Source'.+parseSource :: StructureParser (GDRef Source)+parseSource = parseTag (GDTag "SOUR")$ \(_, children) ->+ runMultiMonad children$ Source+ <$> parseOptional parseSourceData+ <*> parseOptional (parseTextTag (GDTag "AUTH"))+ <*> parseOptional (parseTextTag (GDTag "TITL"))+ <*> parseOptional (parseTextTag (GDTag "ABBR"))+ <*> parseOptional (parseTextTag (GDTag "PUBL"))+ <*> parseOptional (parseTextTag (GDTag "TEXT"))+ <*> parseMulti parseRepositoryCitation+ <*> parseMulti parseUserReference+ <*> parseOptional parseRIN+ <*> parseOptional parseChangeDate+ <*> parseMulti parseNote+ <*> parseMulti parseMultimedia++-- | Parse a 'Submitter'.+parseSubmitter :: GDTag -> StructureParser (GDRef Submitter)+parseSubmitter tag = parseTag tag$ \(_, children) ->+ runMultiMonad children$ Submitter+ <$> parseRequired (GDTag "NAME")+ ((fmap.fmap.fmap) getPersonalName parseName)+ <*> (parseContactDetails >>= (parseOptional.parseAddress))+ <*> parseOptional parseMultimedia+ <*> parseMulti parseLanguage+ <*> parseOptional parseRFN+ <*> parseOptional parseRIN+ <*> parseMulti parseNote+ <*> parseOptional parseChangeDate++-- | Parse a 'Submission'.+parseSubmission :: StructureParser (GDRef Submission)+parseSubmission = parseTag (GDTag "SUBN")$ \(_, children) ->+ runMultiMonad children$ Submission+ <$> parseOptional (parseSubmitter (GDTag "SUBM"))+ <*> parseOptional (parseTextTag (GDTag "FAMF"))+ <*> parseOptional (parseTextTag (GDTag "TEMP"))+ <*> parseOptional (parseWordTag (GDTag "ANCE"))+ <*> parseOptional (parseWordTag (GDTag "DESC"))+ <*> parseOptional (parseBoolTag (GDTag "ORDI"))+ <*> parseOptional parseRIN+ <*> parseMulti parseNote+ <*> parseOptional parseChangeDate++-- | Parse a 'RestrictionNotice'.+parseRestrictionNotice :: StructureParser RestrictionNotice+parseRestrictionNotice = parseNoLinkTag (GDTag "RESN")$ \(t, _) ->+ case parseMaybe parser (gdIgnoreEscapes t) of+ Nothing -> throwError.FormatError$+ "Bad restriction notice " <> (T.show t)+ Just r -> return r+ where parser :: Parser RestrictionNotice+ parser = (Confidential <$ "confidential")+ <|> (Locked <$ "locked")+ <|> (Privacy <$ "privacy")++-- | Parse a list of 'FamilyEvent's.+parseFamilyEvent :: MultiMonad [FamilyEvent]+parseFamilyEvent = do+ concat <$> mapM (parseMulti.familyEventTag) [+ (GDTag "ANUL", const Annuled),+ (GDTag "CENS", const FamCensus),+ (GDTag "DIV", const Divorce),+ (GDTag "DIVF", const DivorceFiled),+ (GDTag "ENGA", const Engagement),+ (GDTag "MARB", const MarriageBann),+ (GDTag "MARC", const MarriageContract),+ (GDTag "MARR", const Marriage),+ (GDTag "MARL", const MarriageLicense),+ (GDTag "MARS", const MarriageSettlement),+ (GDTag "RESI", const Residence),+ (GDTag "EVEN", FamilyEventType)]+ where+ familyEventTag (tag, mkType) = parseNoLinkTag tag$ \(t, children) ->+ runMultiMonad children$ FamilyEvent (mkType$ gdIgnoreEscapes t)+ <$> parseFamilyEventDetail++-- | Parse a 'FamiltyEventDetail'.+parseFamilyEventDetail :: MultiMonad FamilyEventDetail+parseFamilyEventDetail = FamilyEventDetail+ <$> parseOptional (parseAge (GDTag "HUSB"))+ <*> parseOptional (parseAge (GDTag "WIFE"))+ <*> parseEventDetail++-- | Parse an 'EventDetail'.+parseEventDetail :: MultiMonad EventDetail+parseEventDetail = EventDetail+ <$> parseOptional (parseTextTag (GDTag "TYPE"))+ <*> parseOptional parseDateValue+ <*> parseOptional parsePlace+ <*> (parseContactDetails >>= (parseOptional.parseAddress))+ <*> parseOptional (parseTextTag (GDTag "AGNC"))+ <*> parseOptional (parseTextTag (GDTag "RELI"))+ <*> parseOptional (parseTextTag (GDTag "CAUS"))+ <*> parseOptional parseRestrictionNotice+ <*> parseMulti parseNote+ <*> parseMulti parseSourceCitation+ <*> parseMulti parseMultimedia++-- | Parse an AGE tag.+parseAge :: GDTag -> StructureParser Word+parseAge tag = parseNoLinkTag tag$ \(_, children) ->+ runMultiMonad children$+ parseRequired (GDTag "AGE") (parseWordTag (GDTag "AGE"))++-- | Parse a 'SourceData'.+parseSourceData :: StructureParser SourceData+parseSourceData = parseNoLinkTag (GDTag "DATA")$ \(_, children) ->+ runMultiMonad children$ SourceData+ <$> parseMulti parseSourceRecordedEvent+ <*> parseOptional (parseTextTag (GDTag "AGNC"))+ <*> parseMulti parseNote++-- | Parse a 'Place'.+parsePlace :: StructureParser Place+parsePlace = parseNoLinkTag (GDTag "PLAC")$ \(t, children) ->+ runMultiMonad children$ Place+ <$> (pure$ T.splitOn "," . gdIgnoreEscapes$ t)+ <*> parseOptional (parseListTag (GDTag "FORM"))+ <*> parseOptional parsePhoneticPlaceName+ <*> parseOptional parseRomanPlaceName+ <*> parseOptional parseMapCoord+ <*> parseMulti parseNote++-- | Parse a 'PhoneticPlaceName'.+parsePhoneticPlaceName :: StructureParser PhoneticPlaceName+parsePhoneticPlaceName = parseNoLinkTag (GDTag "FONE")$ \(t, children) ->+ runMultiMonad children$ PhoneticPlaceName+ <$> parseRequired (GDTag "TYPE") parsePhoneticType+ <*> (pure . T.splitOn "," . gdIgnoreEscapes$ t)++-- | Parse a 'RomanPlaceName'.+parseRomanPlaceName :: StructureParser RomanPlaceName+parseRomanPlaceName = parseNoLinkTag (GDTag "ROMN")$ \(t, children) ->+ runMultiMonad children$ RomanPlaceName+ <$> parseRequired (GDTag "TYPE") parseRomanType+ <*> (pure . T.splitOn "," . gdIgnoreEscapes$ t)++-- | Parse a 'PhoneticType'.+parsePhoneticType :: StructureParser PhoneticType+parsePhoneticType = parseNoLinkTag (GDTag "TYPE")$ \(t, _) ->+ return$ case trim . T.toUpper . gdIgnoreEscapes$ t of+ "HANGUL" -> Hangul+ "KANA" -> Kana+ v -> PhoneticType v++-- | Parse a 'RomanType'.+parseRomanType :: StructureParser RomanType+parseRomanType = parseNoLinkTag (GDTag "TYPE")$ \(t, _) ->+ return$ case trim . T.toUpper . gdIgnoreEscapes$ t of+ "PINYIN" -> Pinyin+ "ROMAJI" -> Romaji+ "WADEGILES" -> WadeGiles+ v -> RomanType v++-- | Parse a 'MapCoord'.+parseMapCoord :: StructureParser MapCoord+parseMapCoord = parseNoLinkTag (GDTag "MAP")$ \(_, children) ->+ runMultiMonad children$ MapCoord+ <$> parseRequired (GDTag "LATI") ((fmap.fmap.fmap) Longitude$+ parseLongLat (GDTag "LATI") 'N' 'S')+ <*> parseRequired (GDTag "LONG") ((fmap.fmap.fmap) Latitude$+ parseLongLat (GDTag "LONG") 'E' 'W')++-- | Parse a 'Longitude' or 'Latitude' value.+parseLongLat ::+ GDTag -- ^ The tag to parse+ -> Char -- ^ The single character prefix that indicates a positive value. + -> Char -- ^ The single character prefix that indicates a negative value.+ -> StructureParser Double+parseLongLat tag p n = parseNoLinkTag tag$ \(t, _) ->+ case T.uncons . T.toUpper . gdIgnoreEscapes$ t of+ Nothing -> throwError.FormatError$+ "Badly formatted longitude/latitude " <> (T.show t)+ Just (i, r) ->+ if i == p then return$ read . T.unpack$ r+ else if i == n then return$ negate . read . T.unpack$ r+ else throwError.FormatError$+ "Badly formatted longitude/latitude" <> (T.show t)++-- | Parse a 'PersonalName'.+parsePersonalName :: StructureParser PersonalName+parsePersonalName = parseNoLinkTag (GDTag "NAME")$ \(n, children) ->+ runMultiMonad children$ PersonalName+ <$> (pure.getPersonalName.gdIgnoreEscapes$ n)+ <*> parseOptional parseNameType+ <*> parseNamePieces+ <*> parseMulti parsePhoneticName+ <*> parseMulti parseRomanName+ +-- | Extract a 'Name' from a string.+getPersonalName :: T.Text -> Name+getPersonalName = Name <$> reformat <*> (getMiddle . T.splitOn "/")+ where+ reformat = T.unwords . T.words . T.map (\c -> if c == '/' then ' ' else c)+ getMiddle [_, m, _] = Just$ trim m+ getMiddle _ = Nothing++-- | Parse a 'NameType'.+parseNameType :: StructureParser NameType+parseNameType = parseNoLinkTag (GDTag "TYPE")$ \(t', _) ->+ let t = gdIgnoreEscapes t'+ in return . fromMaybe (NameType t) . parseMaybe parser $ t+ where parser :: Parser NameType+ parser = (AKA <$ "aka")+ <|> (BirthName <$ "birth")+ <|> (Immigrant <$ "immigrant")+ <|> (Maiden <$ "maiden")+ <|> (Married <$ "married")++-- | Parse a 'PersonalNamePieces' structure.+parseNamePieces :: MultiMonad PersonalNamePieces+parseNamePieces = PersonalNamePieces+ <$> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "NPFX")))+ <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "GIVN")))+ <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "NICK")))+ <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "SPFX")))+ <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "SURN")))+ <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "NSFX")))+ <*> parseMulti parseNote+ <*> parseMulti parseSourceCitation++-- | Parse a 'PhoneticName'.+parsePhoneticName :: StructureParser PhoneticName+parsePhoneticName = parseNoLinkTag (GDTag "FONE")$ \(t, children) ->+ runMultiMonad children$ PhoneticName+ <$> (pure.getPersonalName.gdIgnoreEscapes$ t)+ <*> parseRequired (GDTag "TYPE") parsePhoneticType+ <*> parseNamePieces++-- | Parse a 'RomanizedName'.+parseRomanName :: StructureParser RomanizedName+parseRomanName = parseNoLinkTag (GDTag "FONE")$ \(t, children) ->+ runMultiMonad children$ RomanizedName+ <$> (pure.getPersonalName.gdIgnoreEscapes$ t)+ <*> parseRequired (GDTag "TYPE") parseRomanType+ <*> parseNamePieces++-- | Parse a 'Sex'.+parseSex :: StructureParser Sex+parseSex = parseNoLinkTag (GDTag "SEX")$ \(t, _) ->+ case trim . T.toUpper . gdIgnoreEscapes $ t of+ "M" -> return Male+ "F" -> return Female+ "U" -> return Undetermined+ _ -> throwError.FormatError$ "Unknown sex code " <> (T.show t)+ +-- | Parse a list of 'IndividualAttribute's.+parseIndividualAttribute :: MultiMonad [IndividualAttribute]+parseIndividualAttribute = do+ concat <$> mapM (parseMulti.attributeTag) [+ (GDTag "CAST", Caste),+ (GDTag "DSCR", PhysicalDescription),+ (GDTag "EDUC", Education),+ (GDTag "IPNO", NationalID),+ (GDTag "NATI", NationalOrigin),+ (GDTag "NCHI", NChildren . read . T.unpack),+ (GDTag "NMR", NMarriages . read . T.unpack),+ (GDTag "OCCU", Occupation),+ (GDTag "PROP", Possessions),+ (GDTag "RELI", Religion),+ (GDTag "RESI", const ResidesAt),+ (GDTag "SSN", SocialSecurity),+ (GDTag "TITL", Title),+ (GDTag "FACT", Fact)]+ where+ attributeTag (tag, mkType) = parseNoLinkTag tag$ \(t, children) ->+ runMultiMonad children$ IndividualAttribute (mkType$ gdIgnoreEscapes t)+ <$> parseIndividualEventDetail++-- | Parse a list of 'IndividualEvent's+parseIndividualEvent :: MultiMonad [IndividualEvent]+parseIndividualEvent = do+ famc <- concat <$> mapM (parseMulti.famcTag)+ [(GDTag "BIRT", Birth), (GDTag "CHR", Christening)]+ adop <- parseMulti.parseNoLinkTag (GDTag "ADOP")$ \(_, children) ->+ runMultiMonad children$ IndividualEvent+ <$> (Adoption <$> parseOptional parseAdopFamilyRef)+ <*> parseIndividualEventDetail+ simple <- concat <$> mapM (parseMulti.eventTag) [+ (GDTag "DEAT", const Death),+ (GDTag "BURI", const Burial),+ (GDTag "CREM", const Cremation),+ (GDTag "BAPM", const Baptism),+ (GDTag "BARM", const BarMitzvah),+ (GDTag "BASM", const BasMitzvah),+ (GDTag "BLES", const Blessing),+ (GDTag "CHRA", const ChristeningAdult),+ (GDTag "CONF", const Confirmation),+ (GDTag "FCOM", const FirstCommunion),+ (GDTag "ORDN", const Ordination),+ (GDTag "NATU", const Naturalization),+ (GDTag "EMIG", const Emigration),+ (GDTag "IMMI", const Immigration),+ (GDTag "CENS", const IndvCensus),+ (GDTag "PROB", const Probate),+ (GDTag "WILL", const Will),+ (GDTag "GRAD", const Graduation),+ (GDTag "RETI", const Retirement),+ (GDTag "EVEN", IndividualEventType)]+ return$ famc ++ adop ++ simple+ where+ eventTag (tag, mkType) = parseNoLinkTag tag$ \(t, children) ->+ runMultiMonad children$ IndividualEvent (mkType$ gdIgnoreEscapes t)+ <$> parseIndividualEventDetail+ famcTag (tag, mkType) = parseNoLinkTag tag$ \(_, children) ->+ runMultiMonad children$ IndividualEvent+ <$> (mkType <$> parseOptional parseFamilyRef)+ <*> parseIndividualEventDetail+ parseFamilyRef = parseLinkTag (GDTag "FAMC") + parseAdopFamilyRef = parseTagFull (GDTag "FAMC") nullrref$ \(lb, children) ->+ case lb of+ Right _ -> throwError.RequiredRef$ "Missing link in FAMC"+ Left f -> runMultiMonad children$+ AdoptionDetail f <$> parseOptional parseParent+ parseParent = parseNoLinkTag (GDTag "ADOP")$ \(t, _) ->+ case trim . T.toUpper . gdIgnoreEscapes $ t of+ "HUSB" -> return Husband+ "WIFE" -> return Wife+ "BOTH" -> return BothParents+ _ -> throwError.FormatError$ "Invalid parent " <> (T.show t)++-- | Parse an 'IndividualEventDetail'.+parseIndividualEventDetail :: MultiMonad IndividualEventDetail+parseIndividualEventDetail = IndividualEventDetail+ <$> parseEventDetail+ <*> parseOptional (parseWordTag (GDTag "AGE"))++-- | Parse a 'ChildToFamilyLink'.+parseChildToFamilyLink :: StructureParser ChildToFamilyLink+parseChildToFamilyLink = parseTagFull (GDTag "FAMC") nullrref$ \(lb, children) ->+ case lb of+ Right _ -> throwError.RequiredRef$ "Missing link in FAMC"+ Left f -> runMultiMonad children$ ChildToFamilyLink f+ <$> parseOptional parsePedigree+ <*> parseOptional parseChildLinkStatus+ <*> parseMulti parseNote++-- | Parse a 'Pedigree'.+parsePedigree :: StructureParser Pedigree+parsePedigree = parseNoLinkTag (GDTag "PEDI")$ \(t, _) ->+ case trim . T.toUpper . gdIgnoreEscapes$ t of+ "ADOPTED" -> return Adopted+ "BIRTH" -> return ByBirth+ "FOSTER" -> return Foster+ "SEALING" -> return Sealing+ _ -> throwError.FormatError$ "Invalid pedigree code " <> (T.show t)++-- | Parse a 'ChildLinkStatus'.+parseChildLinkStatus :: StructureParser ChildLinkStatus+parseChildLinkStatus = parseNoLinkTag (GDTag "STAT")$ \(t, _) ->+ case trim . T.toUpper . gdIgnoreEscapes$ t of+ "CHALLENGED" -> return Challenged+ "DISPROVEN" -> return Disproved+ "PROVEN" -> return Proven+ _ -> throwError.FormatError$ "Invalid child link status " <> (T.show t)++-- | Parse a 'SpouseToFamilyLink'.+parseSpouseToFamilyLink :: StructureParser SpouseToFamilyLink+parseSpouseToFamilyLink = parseTagFull (GDTag "FAMS") nullrref$+ \(lb, children) ->+ case lb of+ Right _ -> throwError.RequiredRef$ "Missing link in FAMS"+ Left f -> runMultiMonad children$ SpouseToFamilyLink f+ <$> parseMulti parseNote++-- | Parse an 'Association'.+parseAssociation :: StructureParser Association+parseAssociation = parseTagFull (GDTag "ASSO") nullrref$ \(lb, children) ->+ case lb of+ Right _ -> throwError.RequiredRef$ "Missing link in ASSO"+ Left i -> runMultiMonad children$ Association i+ <$> parseRequired (GDTag "RELA") (parseTextTag (GDTag "RELA"))+ <*> parseMulti parseSourceCitation+ <*> parseMulti parseNote++-- | Parse a 'SourceRecordedEvent'.+parseSourceRecordedEvent :: StructureParser SourceRecordedEvent+parseSourceRecordedEvent = parseNoLinkTag (GDTag "EVEN")$+ \(recorded, children) ->+ runMultiMonad children$ SourceRecordedEvent+ <$> (pure . catMaybes . fmap getEventType+ . T.splitOn "," . gdIgnoreEscapes$ recorded)+ <*> parseOptional fullParseDatePeriod+ <*> parseOptional (parseListTag (GDTag "PLAC"))+ where+ fullParseDatePeriod = parseNoLinkTag (GDTag "DATE")$ \(date, _) ->+ case parseDatePeriod date of+ Just v -> return v+ Nothing -> throwError.FormatError$+ "Badly formatted date period: " <> (T.show date)++-- | Parse a 'RepositoryCitation'.+parseRepositoryCitation :: StructureParser RepositoryCitation+parseRepositoryCitation = parseTagFull (GDTag "REPO") nullrref$+ \(lb, children) ->+ let repo = case lb of+ Left v -> Just v+ Right _ -> Nothing+ in runMultiMonad children$ RepositoryCitation repo+ <$> parseMulti parseNote+ <*> parseOptional parseCallNumber++-- | Parse a 'CallNumber'.+parseCallNumber :: StructureParser CallNumber+parseCallNumber = parseNoLinkTag (GDTag "CALN")$ \(n, children) ->+ runMultiMonad children$ CallNumber (gdIgnoreEscapes n)+ <$> parseOptional (parseMultimediaType (GDTag "MEDI"))++-- | Parse a 'SourceCitation'.+parseSourceCitation :: StructureParser SourceCitation+parseSourceCitation = parseTagFull (GDTag "SOUR") nullrref$+ \(lb, children) ->+ case lb of+ Left source ->+ runMultiMonad children$ SourceCitation (Right source)+ <$> parseOptional (parseTextTag (GDTag "PAGE"))+ <*> parseMulti parseMultimedia+ <*> parseMulti parseNote+ <*> parseOptional parseQuality+ Right description ->+ runMultiMonad children$ SourceCitation+ <$> (Left . SourceDescription (gdIgnoreEscapes description)+ <$> parseMulti (parseTextTag (GDTag "TEXT")))+ <*> pure Nothing+ <*> parseMulti parseMultimedia+ <*> parseMulti parseNote+ <*> parseOptional parseQuality++-- | Parse a 'GedcomFormat'.+parseGedcomFormat :: StructureParser GedcomFormat+parseGedcomFormat = parseNoLinkTag (GDTag "GEDC")$ \(_, children) ->+ runMultiMonad children$ GedcomFormat+ <$> parseRequired (GDTag "VERS") parseVersion+ <*> parseRequired (GDTag "FORM") parseGedcomForm++-- | Parse a 'GedcomForm'.+parseGedcomForm :: StructureParser GedcomForm+parseGedcomForm = parseNoLinkTag (GDTag "FORM")$ \(t, _) ->+ return$ if (T.toUpper . gdIgnoreEscapes$ t) == "LINEAGE-LINKED"+ then GedcomLineageLinked+ else GedcomUnsupported (gdIgnoreEscapes t)++-- | Parse a 'Charset'.+parseCharset :: StructureParser Charset+parseCharset = parseNoLinkTag (GDTag "CHAR")$ \(cs, children) ->+ runMultiMonad children$ Charset (gdIgnoreEscapes cs)+ <$> parseOptional parseVersion++-- | Parse a 'ChangeDate'.+parseChangeDate :: StructureParser ChangeDate+parseChangeDate = parseNoLinkTag (GDTag "CHAN")$ \(_, children) ->+ runMultiMonad children$ ChangeDate+ <$> parseRequired (GDTag "DATE") parseExactDateTime+ <*> parseOptional parseNote++-- | Parse 'ContactDetails'.+parseContactDetails :: MultiMonad ContactDetails+parseContactDetails = ContactDetails+ <$> parseMulti (parseTextTag (GDTag "PHON"))+ <*> parseMulti (parseTextTag (GDTag "EMAIL"))+ <*> parseMulti (parseTextTag (GDTag "FAX"))+ <*> parseMulti (parseTextTag (GDTag "WWW"))++-- | Parse an 'Address'.+parseAddress :: ContactDetails -> StructureParser Address+parseAddress contacts = parseNoLinkTag (GDTag "ADDR")$ \(addr, children) ->+ runMultiMonad children$ Address (gdIgnoreEscapes addr)+ <$> parseOptional (parseTextTag (GDTag "CITY"))+ <*> parseOptional (parseTextTag (GDTag "STAE"))+ <*> parseOptional (parseTextTag (GDTag "POS"))+ <*> parseOptional (parseTextTag (GDTag "CTRY"))+ <*> pure contacts++-- | Parse a 'DateValue'.+parseDateValue :: StructureParser DateValue+parseDateValue = parseNoLinkTag (GDTag "DATE")$ \(t, _) ->+ let date = (DateApproxV <$> parseDateApprox t)+ <|> (DateRangeV <$> parseDateRange t)+ <|> (DatePeriodV <$> parseDatePeriod t)+ <|> (parseDatePhrase t)+ <|> (DateV <$> parseDate t)+ in case date of+ Just x -> return x+ Nothing -> throwError.FormatError$ "Invalid date format " <> (T.show t)++-- | Decode a calendar escape sequence to a 'Calendar'.+decodeCalendarEscape :: Maybe GDEscape -> Calendar+decodeCalendarEscape Nothing = Gregorian+decodeCalendarEscape (Just (GDEscape c)) = case T.toUpper c of+ "DGREGORIAN" -> Gregorian+ "DJULIAN" -> Julian+ "DHEBREW" -> Hebrew+ "DFRENCH" -> French+ "DROMAN" -> Julian+ "DUNKNOWN" -> Gregorian+ _ -> Gregorian++-- | Prepare text for parsing a 'DateValue'.+prepareDateText :: [(Maybe GDEscape, T.Text)] -> [(Maybe GDEscape, T.Text)]+prepareDateText = gdFilterEscapes [+ GDEscape "DGREGORIAN",+ GDEscape "DJULIAN",+ GDEscape "DHEBREW",+ GDEscape "DFRENCH",+ GDEscape "DROMAN",+ GDEscape "DUNKNOWN"]++-- | Attempt to extract a 'DatePeriod' from a string with escape sequences.+parseDatePeriod :: [(Maybe GDEscape, T.Text)] -> Maybe DatePeriod+parseDatePeriod t = case prepareDateText t of+ ((mCalendarEscape1, t1'):rest) ->+ let+ calendar1 = decodeCalendarEscape mCalendarEscape1+ t1 = trim$ T.toUpper t1'+ from = trim <$> T.stripPrefix "FROM" t1+ to = trim <$> T.stripPrefix "TO" t1+ in case to of+ Just r -> DateTo <$> getDate calendar1 r+ Nothing -> case from of+ Nothing -> Nothing+ Just r ->+ let topcs = T.splitOn "TO"$ r+ in case topcs of+ [mfdate, mto] -> DateFrom+ <$> getDate calendar1 (trim mfdate)+ <*> (pure$ getDate calendar1 (trim mto))+ [mfdate] -> case rest of+ [] -> DateFrom+ <$> getDate calendar1 (trim mfdate) <*> (pure Nothing)+ ((mCalendarEscape2, t2'):_) ->+ let+ calendar2 = decodeCalendarEscape mCalendarEscape2+ t2 = trim$ T.toUpper t2'+ to2 = trim <$> T.stripPrefix "TO" t2+ in case to2 of+ Nothing -> Nothing+ Just r2 -> DateFrom+ <$> getDate calendar1 (trim mfdate)+ <*> (pure$ getDate calendar2 (trim r2))+ _ -> Nothing+ _ -> Nothing++-- | Attempt to extract a 'DateRange' from a string with escape sequences.+parseDateRange :: [(Maybe GDEscape, T.Text)] -> Maybe DateRange+parseDateRange t = case prepareDateText t of+ ((mCalendarEscape1, t1):rest) ->+ let+ calendar1 = decodeCalendarEscape mCalendarEscape1+ (pref, date1) = second trim . T.splitAt 3 . T.toUpper . trim $ t1+ in case pref of+ "BEF" -> DateBefore <$> getDate calendar1 date1+ "AFT" -> DateAfter <$> getDate calendar1 date1+ "BET" -> case T.splitOn "AND" date1 of+ [d1, date2'] -> DateBetween+ <$> getDate calendar1 d1+ <*> getDate calendar1 (trim date2')+ [d1] -> case rest of+ [] -> Nothing+ ((mCalendarEscape2, t2):_) ->+ let calendar2 = decodeCalendarEscape mCalendarEscape2+ in DateBetween+ <$> getDate calendar1 d1+ <*> getDate calendar2 (trim t2)+ _ -> Nothing+ _ -> Nothing+ _ -> Nothing++-- | Attempt to extract a 'DateApprox' from a string with escape sequences.+parseDateApprox :: [(Maybe GDEscape, T.Text)] -> Maybe DateApprox+parseDateApprox t = case prepareDateText t of+ ((mCalendarEscape1, t1):_) ->+ let+ calendar1 = decodeCalendarEscape mCalendarEscape1+ (pref, date) = second trim . T.splitAt 3 . T.toUpper . trim $ t1+ cons = case pref of+ "ABT" -> Just DateAbout+ "CAL" -> Just DateCalculated+ "EST" -> Just DateEstimated+ _ -> Nothing+ in cons <*> getDate calendar1 date+ _ -> Nothing++-- | Attempt to extract a 'DatePhrase' from a string with escape sequences.+parseDatePhrase :: [(Maybe GDEscape, T.Text)] -> Maybe DateValue+parseDatePhrase t = case prepareDateText t of+ ((mCalendarEscape1, t1):_) ->+ let+ calendar1 = decodeCalendarEscape mCalendarEscape1+ int = trim <$> T.stripPrefix "INT" t1+ opp = trim <$> T.stripPrefix "(" t1+ in case int of+ Nothing -> case opp of+ Nothing -> Nothing+ Just phrase -> Just$+ DatePhrase Nothing (trim . T.dropEnd 1$ phrase)+ Just rest -> case trim <$> T.splitOn "(" rest of+ [date, phrase] -> Just$ + DatePhrase (getDate calendar1 date) (trim . T.dropEnd 1$ phrase)+ _ -> Nothing+ _ -> Nothing++-- | Attempt to extract a 'Date' from a string with escape sequences.+parseDate :: [(Maybe GDEscape, T.Text)] -> Maybe Date+parseDate t = case prepareDateText t of+ ((mCalendarEscape, cal):rest) ->+ let calendar = decodeCalendarEscape mCalendarEscape+ in getDate calendar (cal <> gdIgnoreEscapes rest)+ _ -> Nothing++-- | Parse a 'Date' from a given string assuming the given 'Calendar'.+getDate :: Calendar -> T.Text -> Maybe Date+getDate calendar = parseMaybe parser+ where+ yearParser = case calendar of+ Gregorian -> yearGreg+ _ -> read <$> count' 1 4 digitChar+ parseYear = (\y bc -> Year$ if bc then (0 - y) else y)+ <$> yearParser <*> ((True <$ "B.C.") <|> pure False)+ parser :: Parser Date+ parser =+ (try$ Date calendar+ <$> (Just . read <$> count' 1 2 digitChar)+ <*> (gdDelim >> (Just <$> parseMonth))+ <*> (gdDelim >> parseYear))+ <|> (try$ Date calendar Nothing+ <$> (gdDelim >> (Just <$> parseMonth))+ <*> (gdDelim >> parseYear))+ <|> (Date calendar Nothing Nothing+ <$> (gdDelim >> parseYear))+ parseMonth = case calendar of+ Gregorian -> month+ Julian -> month+ Hebrew -> monthHeb+ French -> monthFr+ +-- | Parse an exact date.+parseExactDate :: StructureParser UTCTime+parseExactDate = parseNoLinkTag (GDTag "DATE")$ \(date, _) ->+ case parseMaybe dateExact (gdIgnoreEscapes date) of+ Nothing -> throwError.FormatError$ "Bad date \"" <> (T.show date) <> "\""+ Just (d, m, y) ->+ return$ UTCTime+ (fromGregorian (fromIntegral y) (fromIntegral m) d)+ (secondsToDiffTime 0)++-- | Parse an exact date and time.+parseExactDateTime :: StructureParser UTCTime+parseExactDateTime = parseNoLinkTag (GDTag "DATE")$ \(date, children) -> do+ mtime <- runMultiMonad children$ parseOptional (parseTextTag (GDTag "TIME"))++ dt <- case mtime of+ Nothing -> return$ secondsToDiffTime 0+ Just t -> case parseMaybe timeValue t of+ Nothing -> throwError.FormatError$ "Bad time \"" <> (T.show t) <> "\""+ Just Nothing -> return$ secondsToDiffTime 0+ Just (Just time) -> return$ timeToPicos time++ case parseMaybe dateExact (gdIgnoreEscapes date) of+ Nothing -> throwError.FormatError$ "Bad date \"" <> (T.show date) <> "\""+ Just (d, m, y) -> return$ UTCTime+ (fromGregorian (fromIntegral y) (fromIntegral m) d) dt++-- | Parse a 'Multimedia' record.+parseMultimediaRecord :: StructureParser (GDRef Multimedia)+parseMultimediaRecord = parseMultimediaRaw (GDTag "TYPE")++-- | Parse a 'Multimedia' link.+parseMultimedia :: StructureParser (GDRef Multimedia)+parseMultimedia = parseMultimediaRaw (GDTag "MEDI")++-- | Actual parser for 'Multimedia' values.+parseMultimediaRaw :: GDTag -> StructureParser (GDRef Multimedia)+parseMultimediaRaw typeTag = parseTag (GDTag "OBJE")$ \(_, children) ->+ runMultiMonad children$ Multimedia+ <$> ((parseOptional (parseMultimediaFormat typeTag)) >>=+ (parseMulti.(parseMultimediaFile typeTag)))+ <*> parseOptional (parseTextTag (GDTag "TITL"))+ <*> parseMulti parseUserReference+ <*> parseOptional parseRIN+ <*> parseMulti parseNote+ <*> parseMulti parseSourceCitation+ <*> parseOptional parseChangeDate++-- | Parse a 'MultimediaFile'.+parseMultimediaFile ::+ GDTag -> Maybe MultimediaFormat ->+ StructureParser MultimediaFile+parseMultimediaFile typeTag mf = parseNoLinkTag (GDTag "FILE")$+ \(name, children) -> do+ (mc, title) <- runMultiMonad children$ (,)+ <$> parseOptional (parseMultimediaFormat typeTag)+ <*> parseOptional (parseTextTag (GDTag "TITL"))+ case mc <|> mf of+ Nothing -> throwError.TagError$ "Missing FORM tag for file format"+ Just c -> return$ MultimediaFile (gdIgnoreEscapes name) c title++-- | Parse a 'MultimediaFormat'.+parseMultimediaFormat :: GDTag -> StructureParser MultimediaFormat+parseMultimediaFormat tag = parseNoLinkTag (GDTag "FORM")$ \(v', children) ->+ let v = gdIgnoreEscapes v'+ in runMultiMonad children$ MultimediaFormat+ (fromMaybe (MF_OTHER v)$ parseMaybe parser v)+ <$> parseOptional (parseMultimediaType tag)++ where+ parser :: Parser MultimediaFileFormat+ parser = (MF_BMP <$ "bmp")+ <|> (MF_GIF <$ "gif")+ <|> (MF_JPG <$ "jpg")+ <|> (MF_OLE <$ "ole")+ <|> (MF_PCX <$ "pcx")+ <|> (MF_TIF <$ "tif")+ <|> (MF_WAV <$ "wav")++-- | Parse a 'MultimediaType'.+parseMultimediaType :: GDTag -> StructureParser MultimediaType+parseMultimediaType tag = parseNoLinkTag tag$ \(v', _) ->+ let v = gdIgnoreEscapes v'+ in return.fromMaybe (MT_OTHER v)$ parseMaybe parser v+ where+ parser :: Parser MultimediaType+ parser = (MT_AUDIO <$ "audio")+ <|> (MT_BOOK <$ "book")+ <|> (MT_CARD <$ "card")+ <|> (MT_ELECTRONIC <$ "electronic")+ <|> (MT_FICHE <$ "fiche")+ <|> (MT_FILM <$ "film")+ <|> (MT_MAGAZINE <$ "magazine")+ <|> (MT_MANUSCRIPT <$ "manuscript")+ <|> (MT_MAP <$ "map")+ <|> (MT_NEWSPAPER <$ "newspaper")+ <|> (MT_PHOTO <$ "photo")+ <|> (MT_TOMBSTONE <$ "tombstone")+ <|> (MT_VIDEO <$ "video")++-- | Parse a 'FamilyEventType'.+getFamilyEventType :: T.Text -> Maybe FamilyEventType+getFamilyEventType = parseMaybe parser+ where+ parser :: Parser FamilyEventType+ parser = (Annuled <$ "ANUL")+ <|> (FamCensus <$ "CENS")+ <|> (Divorce <$ "DIV")+ <|> (DivorceFiled <$ "DIVF")+ <|> (Engagement <$ "ENGA")+ <|> (MarriageBann <$ "MARB")+ <|> (MarriageContract <$ "MARC")+ <|> (Marriage <$ "MARR")+ <|> (MarriageLicense <$ "MARL")+ <|> (MarriageSettlement <$ "MARS")+ <|> (Residence <$ "RESI")+ <|> (FamilyEventType . T.pack <$>+ ("EVEN" *> gdDelim *> many anyChar))++-- | Parse an 'IndividualEventType'.+getIndividualEventType :: T.Text -> Maybe IndividualEventType+getIndividualEventType = parseMaybe parser+ where+ parser :: Parser IndividualEventType+ parser = (Birth Nothing <$ ("BIRTH"+ *> optional (gdDelim >> "Y")))+ <|> (Christening Nothing <$ ("CHR"+ *> optional (gdDelim >> "Y")))+ <|> (Death <$ ("DEAT"+ *> optional (gdDelim >> "Y")))+ <|> (Burial <$ "BURI")+ <|> (Cremation <$ "CREM")+ <|> (Adoption Nothing <$ "ADOP")+ <|> (Baptism <$ "BAPM")+ <|> (BarMitzvah <$ "BARM")+ <|> (BasMitzvah <$ "BASM")+ <|> (Blessing <$ "BLES")+ <|> (ChristeningAdult <$ "CHRA")+ <|> (Confirmation <$ "CONF")+ <|> (FirstCommunion <$ "FCOM")+ <|> (Ordination <$ "ORDN")+ <|> (Naturalization <$ "NATU")+ <|> (Emigration <$ "EMIG")+ <|> (Immigration <$ "IMMI")+ <|> (IndvCensus <$ "CENS")+ <|> (Probate <$ "PROB")+ <|> (Will <$ "WILL")+ <|> (Graduation <$ "GRAD")+ <|> (Retirement <$ "RETI")+ <|> (IndividualEventType . T.pack <$>+ ("EVEN" *> gdDelim *> many anyChar))++-- | Parse an 'EventType'.+getEventType :: T.Text -> Maybe EventType+getEventType et =+ let+ t = trim$ T.toUpper et+ fam = getFamilyEventType et+ indv = getIndividualEventType et+ in+ if t == "CENS" then Just Census+ else if (T.take 4 t) == "EVEN" then+ Just . EventType . trim . T.drop 4$ et+ else fmap FamilyEventTypeV fam <|> fmap IndividualEventTypeV indv++-- | Parse a place form structure.+parsePlaceForm :: StructureParser [T.Text]+parsePlaceForm = parseNoLinkTag (GDTag "PLAC")$ \(_, children) ->+ runMultiMonad children$ fromMaybe [].(fmap$ T.splitOn ",") <$>+ parseOptional (parseTextTag (GDTag "FORM"))++-- | Parse a 'UserReference'.+parseUserReference :: StructureParser UserReference+parseUserReference = parseNoLinkTag (GDTag "REFN")$ \(i, children) ->+ runMultiMonad children$ UserReference (gdIgnoreEscapes i)+ <$> parseOptional (parseTextTag (GDTag "TYPE"))++-- | Parse a version structure.+parseVersion :: StructureParser T.Text+parseVersion = parseTextTag (GDTag "VERS")++-- | Parse a NAME tag.+parseName :: StructureParser T.Text+parseName = parseTextTag (GDTag "NAME")++-- | Parse a copyright tag.+parseCopyright :: StructureParser T.Text+parseCopyright = parseTextTag (GDTag "COPR")++-- | Parse a file name.+parseFile :: StructureParser FilePath+parseFile = (fmap.fmap.fmap) T.unpack$ parseTextTag (GDTag "FILE")++-- | Parse an 'AFN'.+parseAFN :: StructureParser AFN+parseAFN = (fmap.fmap.fmap) AFN$ parseTextTag (GDTag "AFN")++-- | Parse a 'RFN'.+parseRFN :: StructureParser RFN+parseRFN = (fmap.fmap.fmap) RFN$ parseTextTag (GDTag "RFN")++-- | Parse a 'RIN'.+parseRIN :: StructureParser RIN+parseRIN = (fmap.fmap.fmap) RIN$ parseTextTag (GDTag "RIN")++-- | Parse a 'Language'.+parseLanguage :: StructureParser Language+parseLanguage = (fmap.fmap.fmap) (Language) $ parseTextTag (GDTag "LANG")++-- | Parse a 'QualityAssessment'.+parseQuality :: StructureParser QualityAssessment+parseQuality = (fmap.fmap.fmap) QualityAssessment $ parseWordTag (GDTag "QUAY")++-- | Parse a boolean value.+parseBoolTag :: GDTag -> StructureParser Bool+parseBoolTag tag = parseNoLinkTag tag$ \(v, _) ->+ case parseMaybe ynParser (gdIgnoreEscapes v) of+ Nothing -> throwError.FormatError$ "Expected boolean, saw " <> (T.show v)+ Just yn -> return yn+ where+ ynParser :: Parser Bool+ ynParser = (True <$ "yes") <|> (False <$ "no")++-- | Parse a Word value.+parseWordTag :: GDTag -> StructureParser Word+parseWordTag tag = parseNoLinkTag tag$ \(v, _) ->+ case parseMaybe parser (gdIgnoreEscapes v) of+ Nothing -> throwError.FormatError$ "Expected number, saw " <> (T.show v)+ Just n -> return . read $ n+ where+ parser :: Parser String+ parser = many digitChar++-- | Extract the text from a tag.+parseTextTag :: GDTag -> StructureParser T.Text+parseTextTag tag = parseNoLinkTag tag (return.gdIgnoreEscapes.fst)++-- | Extract a list of comma separated values from a tag.+parseListTag :: GDTag -> StructureParser [T.Text]+parseListTag tag =+ parseNoLinkTag tag (return . split . trim . gdIgnoreEscapes . fst)+ where+ split "" = []+ split s = T.splitOn "," s++-- | Handler for tags that cannot contain cross references.+type NoLinkHandler a =+ ([(Maybe GDEscape, T.Text)], [GDTree]) -> StructureMonad a++-- | Handler for general tags.+type TagHandler b a =+ (Either (GDRef b) [(Maybe GDEscape, T.Text)], [GDTree])+ -> StructureMonad a++-- | A function that adds references to the cross reference table.+type RegisterRef a = GDTag -> GDXRefID -> a -> StructureMonad ()++-- | Don't add any references.+nullrref :: Typeable a => RegisterRef a+nullrref _ _ _ = return ()++-- | Add direct references only.+defrref :: Typeable a => RegisterRef (GDRef a)+defrref _ thisID (GDStructure a) = addReference thisID a+defrref tag _ _ = throwError.UnexpectedRef$+ "Referenced structure references another structure " <> (T.show tag)++-- | Parse a tag which is either a GEDCOM structure, or a reference to the+-- expected GEDCOM structure.+parseTag :: Typeable a+ => GDTag -- ^ The tag to parse.+ -> NoLinkHandler a -- ^ A handler for the tag+ -> StructureParser (GDRef a)+parseTag tag handler = parseTagFull tag defrref$ \(lb, children) ->+ case lb of+ Left ref -> return ref+ Right text -> GDStructure <$> handler (text, children)++-- | Parse a tag which cannot contain a cross reference (i.e. the tag must+-- contain the structure itself, not a reference to another structure).+parseNoLinkTag :: Typeable a+ => GDTag -- ^ The tag to parse.+ -> NoLinkHandler a -- ^ A handler for the tag.+ -> StructureParser a+parseNoLinkTag tag handler = parseTagFull tag nullrref$ \(lb, children) ->+ case lb of+ Left _ -> throwError.UnexpectedRef$+ "Cannot follow cross references on " <> (T.show tag)+ Right text -> handler (text, children)++-- | Parse a tag which must contain a cross reference to another structure, not+-- the structure itself.+parseLinkTag :: Typeable a => GDTag -> StructureParser (GDRef a)+parseLinkTag tag = parseTagFull tag nullrref$ \(lb, _) ->+ case lb of+ Left ref -> return ref+ Right _ -> throwError.RequiredRef$+ "Expected cross reference was missing in " <> (T.show tag)++-- | The most general tag parsing function.+parseTagFull :: Typeable a+ => GDTag -- ^ The tag to parse.+ -> RegisterRef a -- ^ How to register cross references.+ -> TagHandler b a -- ^ How to convert the tag into a GEDCOM structure.+ -> StructureParser a+parseTagFull tag rref handler t@(GDTree (GDLine _ mthisID tag' v) children) =+ if tag /= tag' then return$ Left t else do+ r <- case v of+ Nothing -> Right <$> (handler.(first Right)$ parseCont mempty children)+ Just (GDXRefIDV xref) -> do+ Right <$> (handler (Left (GDXRef xref), children))+ Just (GDLineItemV l1) ->+ Right <$> (handler.(first Right)$ parseCont l1 children)+ case (mthisID, r) of+ (Just thisID, Right rv) -> rref tag thisID rv+ _ -> return ()+ return r++-- | Handle CONT and CONC tags.+parseCont ::+ GDLineItem -- ^ The value of the first line+ -> [GDTree] -- ^ The sub tree+ -> ([(Maybe GDEscape, T.Text)], [GDTree]) -- ^ The concatenation of the values of all the CONT and CONC tags, and the remaining tags.+parseCont l1 children =+ bimap assemble (fmap snd).span (isJust.fst)$+ zipWith (\l r -> (cont l <|> conc l, r)) children children+ where+ assemble = gdLineData . mconcat . (l1:) . catMaybes . fmap fst+ cont (GDTree (GDLine _ _ (GDTag "CONT") (Just (GDLineItemV l))) _) =+ Just$ GDLineItem [(Nothing, "\r\n")] <> l+ cont _ = Nothing+ conc (GDTree (GDLine _ _ (GDTag "CONC") (Just (GDLineItemV l))) _) =+ Just$ gdTrimLineItem l+ conc _ = Nothing+
− src/Data/Gedcom/LineParser.hs
@@ -1,147 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-}--{-|-Module: Data.Gedcom.LineParser-Description: Low-level GEDCOM parser-Copyright: (c) Callum Lowcay, 2017-License: BSD3-Maintainer: cwslowcay@gmail.com-Stability: experimental-Portability: GHC--This module parses a Text string into a GEDCOM syntax tree.---}-module Data.Gedcom.LineParser (- gdRoot, gdDelim-) where--import Control.Monad-import Data.Char-import Data.Gedcom.Common-import Data.Gedcom.Internal.Common-import Data.Maybe-import Data.Monoid-import qualified Data.Text.All as T-import Text.Megaparsec---- | Parse any_char.-gdAnyChar :: Parser String-gdAnyChar = (fmap (:[]) gdNonAt) <|> string "@@"---- | Parse non_at.-gdNonAt :: Parser Char-gdNonAt = satisfy (\c -> (not.isControl) c && c /= '@' && c /= '\x7F')---- | Parse alphanum.-gdAlphaNum :: Parser Char-gdAlphaNum = alphaNumChar <|> char '_'---- | Parse delim.-gdDelim :: Parser (Maybe Char)-gdDelim = optional$ char '\x20'---- | Parse escape.-gdEscape :: Parser GDEscape-gdEscape = GDEscape . T.pack <$>- (string "@#" *> gdEscapeText <* char '@' <* (optional$ char ' '))---- | Parse escape_text.-gdEscapeText :: Parser String-gdEscapeText = concat <$> many gdAnyChar---- | Parse level.-gdLevel :: Parser GDLevel-gdLevel = GDLevel . read <$> count' 1 2 digitChar <* gdDelim---- | Parse line_item.-gdLineItem :: Parser GDLineItem-gdLineItem = fmap GDLineItem . some$- (,) <$> optional gdEscape <*> (T.pack . concat <$> some gdAnyChar)---- | Parse pointer.-gdPointer :: Parser GDXRefID-gdPointer = char '@' *> plabel <* char '@'- where plabel = fmap (GDXRefID . T.pack)$- (:) <$> gdAlphaNum <*> (many gdNonAt)---- | Parse line_value-gdLineValue :: Parser GDLineValue-gdLineValue = eitherP gdPointer gdLineItem <&> \x -> case x of- Left v -> GDXRefIDV v- Right v -> GDLineItemV v---- | Parse optional_line_value.-gdOptionalLineValue :: Parser GDLineValue-gdOptionalLineValue = gdDelim *> gdLineValue---- | Parse optional_xref_ID.-gdOptionalXRefID :: Parser (Maybe GDXRefID)-gdOptionalXRefID = gdXRefID <* gdDelim---- | Parse tag.-gdTag :: Parser GDTag-gdTag = GDTag . T.toUpper . T.pack <$> many gdAlphaNum---- | parse terminator.-gdTerminator :: Parser String-gdTerminator = string "\n" <|> string "\r" <|> string "\r\n" <|> string "\n\r"---- | Parse xref_ID.-gdXRefID :: Parser (Maybe GDXRefID)-gdXRefID = optional $ fmap (\(GDXRefID t) -> GDXRefID t) gdPointer---- | Parse gedcom_line.-gdLine :: Parser GDLine-gdLine = GDLine <$>- gdLevel <*>- gdOptionalXRefID <*>- gdTag <*>- (optional gdOptionalLineValue) <* gdTerminator---- | Convert local ids to global ids.-gdExpandID ::- GDXRefID -- ^ The parent structure's ID- -> GDXRefID -- ^ The local ID.- -> GDXRefID -- ^ A global ID.-gdExpandID (GDXRefID pid) s@(GDXRefID sub) =- case T.uncons sub of- Nothing -> s- Just ('!', _) -> GDXRefID$ pid <> sub- _ -> s---- | Convert local ids to global ids.-gdExpandPointer ::- GDXRefID -- ^ The parent structure's ID.- -> GDLineValue -- ^ The line to update.- -> GDLineValue -- ^ An updated line where local ID's have been made global.-gdExpandPointer pid v = case v of- GDLineItemV _ -> v- GDXRefIDV p -> GDXRefIDV$ gdExpandID pid p---- | Parse a line at a fixed level-gdLineLevel ::- GDXRefID -- ^ The parent ID - -> GDLevel -- ^ The level to parse the line at- -> Parser GDLine-gdLineLevel pid n = do- (GDLine n' xrid tag v) <- gdLine- when (n' /= n)$ fail$ "Saw a " ++ (show tag) ++- " tag at level " ++ (show n') ++- " but expected level was " ++ (show n)- return$ GDLine n' (fmap (gdExpandID pid) xrid) tag (fmap (gdExpandPointer pid) v)---- | Parse a GEDCOM subtree-gdTree ::- GDXRefID -- ^ The parent ID- -> GDLevel -- ^ The level where the subtree is rooted- -> Parser GDTree-gdTree pid n = try$ do- line@(GDLine _ pid' _ _) <- gdLineLevel pid n- GDTree line <$> many (gdTree (fromMaybe pid pid') (n + 1))---- | Parse the raw GEDCOM syntax tree.-gdRoot :: Parser GDRoot-gdRoot = GDRoot <$> (many$ gdTree (GDXRefID "") 0)-
− src/Data/Gedcom/ParseMonads.hs
@@ -1,120 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}--{-|-Module: Data.Gedcom.ParseMonads-Description: Monads for parsing GEDCOM records-Copyright: (c) Callum Lowcay, 2017-License: BSD3-Maintainer: cwslowcay@gmail.com-Stability: experimental-Portability: GHC--This module contains monads and utility functions for extracting GEDCOM records-from the raw syntax tree.---}-module Data.Gedcom.ParseMonads (- StructureParser,- MultiMonad,- runMultiMonad,- parseMulti,- parseOptional,- parseRequired,- StructureMonad,- addReference,- runStructure-) where--import Control.Monad-import Control.Monad.Except-import Control.Monad.State-import Data.Dynamic-import Data.Either-import Data.Foldable-import Data.Gedcom.Common-import Data.Maybe-import Data.Monoid-import qualified Data.Map as M-import qualified Data.Text.All as T---- | A parser that extracts a GEDCOM structure from a GEDCOM subtree.-type StructureParser a =- GDTree -- ^ The subtree to parse.- -> StructureMonad (Either GDTree a) -- ^ Either parsed structure, or the subtree itself if the subtree doesn't contain the expected GEDCOM structure.---- | A Monad for parsing GEDCOM structures out of a list of GEDCOM subtrees.-newtype MultiMonad a =- MultiMonad (ExceptT GDError (StateT [GDTree] StructureMonad) a)- deriving (Monad, Functor, Applicative, MonadError GDError)---- | Run a 'MultiMonad' into a 'StructureMonad'.-runMultiMonad ::- [GDTree] -- ^ The subtrees to parse the structure from.- -> MultiMonad a -- ^ The MultiMonad that does the parsing.- -> StructureMonad a-runMultiMonad children (MultiMonad m) =- ((flip evalStateT) children.runExceptT$ m) >>= rethrowError- where rethrowError x = case x of- Left e -> throwError e- Right v -> return v---- | Parse multiple instances of a structure-parseMulti :: StructureParser a -> MultiMonad [a]-parseMulti p = MultiMonad$ do- ls <- lift$ get- (others, vs) <- lift$ lift$ partitionEithers <$> p `traverse` ls- lift$ put others- return vs---- | Parse an optional instance of a structure-parseOptional :: StructureParser a -> MultiMonad (Maybe a)-parseOptional p = MultiMonad$ do- ls <- lift$ get- (mr, leftover) <-- lift$ lift$ foldrM (\v (r, rest) ->- if isJust r then return (r, v:rest)- else pick v rest.toMaybe <$> p v) (Nothing, []) ls- lift$ put leftover- return mr- where- toMaybe (Left _) = Nothing- toMaybe (Right v) = Just v- pick v rest Nothing = (Nothing, v:rest)- pick _ rest x = (x, rest)---- | Parse a required instance of a structure-parseRequired ::- GDTag -- ^ The tag that identifies the required structure.- -> StructureParser a- -> MultiMonad a-parseRequired tag p = do- r <- parseOptional p- case r of- Just v -> return v- Nothing -> throwError.TagError$- "Could not find required " <> (T.show tag) <> " tag"---- | A monad for parsing an instance of a GEDCOM structure from a GEDCOM--- subtree.-newtype StructureMonad a =- StructureMonad (ExceptT GDError (State (M.Map GDXRefID Dynamic)) a)- deriving (Monad, Functor, Applicative, MonadError GDError)---- | Add a reference to the cross reference table.-addReference :: Typeable a- => GDXRefID -- ^ The cross reference to add.- -> a -- ^ The value the reference will resolve to.- -> StructureMonad ()-addReference thisID value = StructureMonad$ do- alreadySeen <- M.member thisID <$> lift get- when alreadySeen$- throwError.DuplicateRef$ "Duplicate definition of " <> (T.show thisID)- lift.modify$ M.insert thisID (toDyn value)- return ()---- | Run a 'StructureMonad', returning either an error or a value, and the--- cross reference table.-runStructure :: StructureMonad a -> (Either GDError a, M.Map GDXRefID Dynamic)-runStructure (StructureMonad m) = (flip runState) M.empty . runExceptT$ m-
− src/Data/Gedcom/Parser.hs
@@ -1,1123 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecursiveDo #-}-{-# LANGUAGE TupleSections #-}--{-|-Module: Data.Gedcom.Parser-Description: GEDCOM high level parsers-Copyright: (c) Callum Lowcay, 2017-License: BSD3-Maintainer: cwslowcay@gmail.com-Stability: experimental-Portability: GHC--These parsers extract the GEDCOM records from the raw syntax tree.---}-module Data.Gedcom.Parser (- parseGedcom,- parseHeader-) where--import Control.Applicative-import Control.Monad.Except-import Data.Bifunctor-import Data.Dynamic-import Data.Gedcom.Common-import Data.Gedcom.Internal.Common-import Data.Gedcom.LineParser-import Data.Gedcom.ParseMonads-import Data.Gedcom.Structure-import Data.Maybe-import Data.Monoid-import Data.Time.Calendar-import Data.Time.Clock-import qualified Data.Map.Lazy as M-import qualified Data.Text.All as T-import Text.Megaparsec---- | Parse a 'Gedcom' value from the raw GEDCOM syntax tree.-parseGedcom :: GDRoot -> (Either GDError Gedcom, M.Map GDXRefID Dynamic)-parseGedcom (GDRoot children) =- runStructure.runMultiMonad children$ Gedcom- <$> parseRequired (GDTag "HEAD") parseHeader- <*> parseMulti parseFamily- <*> parseMulti (parseIndividual (GDTag "INDI"))- <*> parseMulti parseMultimediaRecord- <*> parseMulti parseNote- <*> parseMulti parseRepository- <*> parseMulti parseSource- <*> parseMulti (parseSubmitter (GDTag "SUBM"))---- | Parse a 'Header'.-parseHeader :: StructureParser Header-parseHeader = parseNoLinkTag (GDTag "HEAD")$ \(_, children) ->- runMultiMonad children$ Header- <$> parseRequired (GDTag "SOUR") parseHeaderSource- <*> parseOptional (parseTextTag (GDTag "DEST"))- <*> parseOptional parseExactDateTime- <*> parseRequired (GDTag "SUBM") (parseSubmitter (GDTag "SUBM"))- <*> parseOptional parseSubmission- <*> parseOptional parseFile- <*> parseOptional parseCopyright- <*> parseRequired (GDTag "GEDC") parseGedcomFormat- <*> parseRequired (GDTag "CHAR") parseCharset- <*> parseOptional parseLanguage- <*> parseOptional parsePlaceForm- <*> parseOptional (parseTextTag (GDTag "NOTE"))---- | Parse a 'HeaderSource'.-parseHeaderSource :: StructureParser HeaderSource-parseHeaderSource = parseNoLinkTag (GDTag "SOUR")$ \(sid, children) ->- runMultiMonad children$ HeaderSource (gdIgnoreEscapes sid)- <$> parseOptional parseVersion- <*> parseOptional parseName- <*> parseOptional parseCorp- <*> parseOptional parseHeaderSourceData---- | Parse a 'Corp'.-parseCorp :: StructureParser Corp-parseCorp = parseNoLinkTag (GDTag "COPR")$ \(name, children) ->- runMultiMonad children$ Corp (gdIgnoreEscapes name)- <$> (parseContactDetails >>= (parseOptional.parseAddress))---- | Parse a 'HeaderSourceData'.-parseHeaderSourceData :: StructureParser HeaderSourceData-parseHeaderSourceData = parseNoLinkTag (GDTag "DATA")$ \(name, children) ->- runMultiMonad children$ HeaderSourceData (gdIgnoreEscapes name)- <$> parseOptional parseExactDate- <*> parseOptional parseCopyright---- | Parse a 'Family'.-parseFamily :: StructureParser (GDRef Family)-parseFamily = parseTag (GDTag "FAM")$ \(_, children) ->- runMultiMonad children$ Family- <$> parseOptional parseRestrictionNotice- <*> parseFamilyEvent- <*> parseOptional (parseIndividual (GDTag "HUSB"))- <*> parseOptional (parseIndividual (GDTag "WIFE"))- <*> parseMulti (parseIndividual (GDTag "CHIL"))- <*> parseOptional (parseWordTag (GDTag "NCHI"))- <*> parseMulti (parseSubmitter (GDTag "SUBM"))- <*> parseMulti parseUserReference- <*> parseOptional parseRIN- <*> parseOptional parseChangeDate- <*> parseMulti parseNote- <*> parseMulti parseSourceCitation- <*> parseMulti parseMultimedia---- | Parse an 'Individual'.-parseIndividual :: GDTag -> StructureParser (GDRef Individual)-parseIndividual tag = parseTag tag$ \(_, children) ->- runMultiMonad children$ Individual- <$> parseOptional parseRestrictionNotice- <*> parseOptional parsePersonalName- <*> parseOptional parseSex- <*> parseIndividualEvent- <*> parseIndividualAttribute- <*> parseMulti parseChildToFamilyLink- <*> parseMulti parseSpouseToFamilyLink- <*> parseMulti (parseSubmitter (GDTag "SUBM"))- <*> parseMulti parseAssociation- <*> parseMulti (parseIndividual (GDTag "ALIA"))- <*> parseMulti (parseSubmitter (GDTag "ANCI"))- <*> parseMulti (parseSubmitter (GDTag "DECI"))- <*> parseOptional parseRFN- <*> parseOptional parseAFN- <*> parseMulti parseUserReference- <*> parseOptional parseRIN- <*> parseOptional parseChangeDate- <*> parseMulti parseNote- <*> parseMulti parseSourceCitation- <*> parseMulti parseMultimedia---- | Parse a 'Node'.-parseNote :: StructureParser (GDRef Note)-parseNote = parseTag (GDTag "NOTE")$ \(t, children) ->- runMultiMonad children$ Note (gdIgnoreEscapes t)- <$> parseMulti parseUserReference- <*> parseOptional parseRIN- <*> parseMulti parseSourceCitation- <*> parseOptional parseChangeDate---- | Parse a 'Repository'.-parseRepository :: StructureParser (GDRef Repository)-parseRepository = parseTag (GDTag "REPO")$ \(_, children) ->- runMultiMonad children$ Repository- <$> parseRequired (GDTag "NAME") parseName- <*> (parseContactDetails >>= (parseOptional.parseAddress))- <*> parseMulti parseNote- <*> parseMulti parseUserReference- <*> parseOptional parseRIN- <*> parseOptional parseChangeDate---- | Parse a 'Source'.-parseSource :: StructureParser (GDRef Source)-parseSource = parseTag (GDTag "SOUR")$ \(_, children) ->- runMultiMonad children$ Source- <$> parseOptional parseSourceData- <*> parseOptional (parseTextTag (GDTag "AUTH"))- <*> parseOptional (parseTextTag (GDTag "TITL"))- <*> parseOptional (parseTextTag (GDTag "ABBR"))- <*> parseOptional (parseTextTag (GDTag "PUBL"))- <*> parseOptional (parseTextTag (GDTag "TEXT"))- <*> parseMulti parseRepositoryCitation- <*> parseMulti parseUserReference- <*> parseOptional parseRIN- <*> parseOptional parseChangeDate- <*> parseMulti parseNote- <*> parseMulti parseMultimedia---- | Parse a 'Submitter'.-parseSubmitter :: GDTag -> StructureParser (GDRef Submitter)-parseSubmitter tag = parseTag tag$ \(_, children) ->- runMultiMonad children$ Submitter- <$> parseRequired (GDTag "NAME")- ((fmap.fmap.fmap) getPersonalName parseName)- <*> (parseContactDetails >>= (parseOptional.parseAddress))- <*> parseOptional parseMultimedia- <*> parseMulti parseLanguage- <*> parseOptional parseRFN- <*> parseOptional parseRIN- <*> parseMulti parseNote- <*> parseOptional parseChangeDate---- | Parse a 'Submission'.-parseSubmission :: StructureParser (GDRef Submission)-parseSubmission = parseTag (GDTag "SUBN")$ \(_, children) ->- runMultiMonad children$ Submission- <$> parseOptional (parseSubmitter (GDTag "SUBM"))- <*> parseOptional (parseTextTag (GDTag "FAMF"))- <*> parseOptional (parseTextTag (GDTag "TEMP"))- <*> parseOptional (parseWordTag (GDTag "ANCE"))- <*> parseOptional (parseWordTag (GDTag "DESC"))- <*> parseOptional (parseBoolTag (GDTag "ORDI"))- <*> parseOptional parseRIN- <*> parseMulti parseNote- <*> parseOptional parseChangeDate---- | Parse a 'RestrictionNotice'.-parseRestrictionNotice :: StructureParser RestrictionNotice-parseRestrictionNotice = parseNoLinkTag (GDTag "RESN")$ \(t, _) ->- case parseMaybe parser (gdIgnoreEscapes t) of- Nothing -> throwError.FormatError$- "Bad restriction notice " <> (T.show t)- Just r -> return r- where parser :: Parser RestrictionNotice- parser = (Confidential <$ string' "confidential")- <|> (Locked <$ string' "locked")- <|> (Privacy <$ string' "privacy")---- | Parse a list of 'FamilyEvent's.-parseFamilyEvent :: MultiMonad [FamilyEvent]-parseFamilyEvent = do- concat <$> mapM (parseMulti.familyEventTag) [- (GDTag "ANUL", const Annuled),- (GDTag "CENS", const FamCensus),- (GDTag "DIV", const Divorce),- (GDTag "DIVF", const DivorceFiled),- (GDTag "ENGA", const Engagement),- (GDTag "MARB", const MarriageBann),- (GDTag "MARC", const MarriageContract),- (GDTag "MARR", const Marriage),- (GDTag "MARL", const MarriageLicense),- (GDTag "MARS", const MarriageSettlement),- (GDTag "RESI", const Residence),- (GDTag "EVEN", FamilyEventType)]- where- familyEventTag (tag, mkType) = parseNoLinkTag tag$ \(t, children) ->- runMultiMonad children$ FamilyEvent (mkType$ gdIgnoreEscapes t)- <$> parseFamilyEventDetail---- | Parse a 'FamiltyEventDetail'.-parseFamilyEventDetail :: MultiMonad FamilyEventDetail-parseFamilyEventDetail = FamilyEventDetail- <$> parseOptional (parseAge (GDTag "HUSB"))- <*> parseOptional (parseAge (GDTag "WIFE"))- <*> parseEventDetail---- | Parse an 'EventDetail'.-parseEventDetail :: MultiMonad EventDetail-parseEventDetail = EventDetail- <$> parseOptional (parseTextTag (GDTag "TYPE"))- <*> parseOptional parseDateValue- <*> parseOptional parsePlace- <*> (parseContactDetails >>= (parseOptional.parseAddress))- <*> parseOptional (parseTextTag (GDTag "AGNC"))- <*> parseOptional (parseTextTag (GDTag "RELI"))- <*> parseOptional (parseTextTag (GDTag "CAUS"))- <*> parseOptional parseRestrictionNotice- <*> parseMulti parseNote- <*> parseMulti parseSourceCitation- <*> parseMulti parseMultimedia---- | Parse an AGE tag.-parseAge :: GDTag -> StructureParser Word-parseAge tag = parseNoLinkTag tag$ \(_, children) ->- runMultiMonad children$- parseRequired (GDTag "AGE") (parseWordTag (GDTag "AGE"))---- | Parse a 'SourceData'.-parseSourceData :: StructureParser SourceData-parseSourceData = parseNoLinkTag (GDTag "DATA")$ \(_, children) ->- runMultiMonad children$ SourceData- <$> parseMulti parseSourceRecordedEvent- <*> parseOptional (parseTextTag (GDTag "AGNC"))- <*> parseMulti parseNote---- | Parse a 'Place'.-parsePlace :: StructureParser Place-parsePlace = parseNoLinkTag (GDTag "PLAC")$ \(t, children) ->- runMultiMonad children$ Place- <$> (pure$ T.splitOn "," . gdIgnoreEscapes$ t)- <*> parseOptional (parseListTag (GDTag "FORM"))- <*> parseOptional parsePhoneticPlaceName- <*> parseOptional parseRomanPlaceName- <*> parseOptional parseMapCoord- <*> parseMulti parseNote---- | Parse a 'PhoneticPlaceName'.-parsePhoneticPlaceName :: StructureParser PhoneticPlaceName-parsePhoneticPlaceName = parseNoLinkTag (GDTag "FONE")$ \(t, children) ->- runMultiMonad children$ PhoneticPlaceName- <$> parseRequired (GDTag "TYPE") parsePhoneticType- <*> (pure . T.splitOn "," . gdIgnoreEscapes$ t)---- | Parse a 'RomanPlaceName'.-parseRomanPlaceName :: StructureParser RomanPlaceName-parseRomanPlaceName = parseNoLinkTag (GDTag "ROMN")$ \(t, children) ->- runMultiMonad children$ RomanPlaceName- <$> parseRequired (GDTag "TYPE") parseRomanType- <*> (pure . T.splitOn "," . gdIgnoreEscapes$ t)---- | Parse a 'PhoneticType'.-parsePhoneticType :: StructureParser PhoneticType-parsePhoneticType = parseNoLinkTag (GDTag "TYPE")$ \(t, _) ->- return$ case trim . T.toUpper . gdIgnoreEscapes$ t of- "HANGUL" -> Hangul- "KANA" -> Kana- v -> PhoneticType v---- | Parse a 'RomanType'.-parseRomanType :: StructureParser RomanType-parseRomanType = parseNoLinkTag (GDTag "TYPE")$ \(t, _) ->- return$ case trim . T.toUpper . gdIgnoreEscapes$ t of- "PINYIN" -> Pinyin- "ROMAJI" -> Romaji- "WADEGILES" -> WadeGiles- v -> RomanType v---- | Parse a 'MapCoord'.-parseMapCoord :: StructureParser MapCoord-parseMapCoord = parseNoLinkTag (GDTag "MAP")$ \(_, children) ->- runMultiMonad children$ MapCoord- <$> parseRequired (GDTag "LATI") ((fmap.fmap.fmap) Longitude$- parseLongLat (GDTag "LATI") 'N' 'S')- <*> parseRequired (GDTag "LONG") ((fmap.fmap.fmap) Latitude$- parseLongLat (GDTag "LONG") 'E' 'W')---- | Parse a 'Longitude' or 'Latitude' value.-parseLongLat ::- GDTag -- ^ The tag to parse- -> Char -- ^ The single character prefix that indicates a positive value. - -> Char -- ^ The single character prefix that indicates a negative value.- -> StructureParser Double-parseLongLat tag p n = parseNoLinkTag tag$ \(t, _) ->- case T.uncons . T.toUpper . gdIgnoreEscapes$ t of- Nothing -> throwError.FormatError$- "Badly formatted longitude/latitude " <> (T.show t)- Just (i, r) ->- if i == p then return$ read . T.unpack$ r- else if i == n then return$ negate . read . T.unpack$ r- else throwError.FormatError$- "Badly formatted longitude/latitude" <> (T.show t)---- | Parse a 'PersonalName'.-parsePersonalName :: StructureParser PersonalName-parsePersonalName = parseNoLinkTag (GDTag "NAME")$ \(n, children) ->- runMultiMonad children$ PersonalName- <$> (pure.getPersonalName.gdIgnoreEscapes$ n)- <*> parseOptional parseNameType- <*> parseNamePieces- <*> parseMulti parsePhoneticName- <*> parseMulti parseRomanName- --- | Extract a 'Name' from a string.-getPersonalName :: T.Text -> Name-getPersonalName = Name <$> reformat <*> (getMiddle . T.splitOn "/")- where- reformat = T.unwords . T.words . T.map (\c -> if c == '/' then ' ' else c)- getMiddle [_, m, _] = Just$ trim m- getMiddle _ = Nothing---- | Parse a 'NameType'.-parseNameType :: StructureParser NameType-parseNameType = parseNoLinkTag (GDTag "TYPE")$ \(t', _) ->- let t = gdIgnoreEscapes t'- in return . fromMaybe (NameType t) . parseMaybe parser $ t- where parser :: Parser NameType- parser = (AKA <$ string' "aka")- <|> (BirthName <$ string' "birth")- <|> (Immigrant <$ string' "immigrant")- <|> (Maiden <$ string' "maiden")- <|> (Married <$ string' "married")---- | Parse a 'PersonalNamePieces' structure.-parseNamePieces :: MultiMonad PersonalNamePieces-parseNamePieces = PersonalNamePieces- <$> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "NPFX")))- <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "GIVN")))- <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "NICK")))- <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "SPFX")))- <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "SURN")))- <*> (fromMaybe [] <$> parseOptional (parseListTag (GDTag "NSFX")))- <*> parseMulti parseNote- <*> parseMulti parseSourceCitation---- | Parse a 'PhoneticName'.-parsePhoneticName :: StructureParser PhoneticName-parsePhoneticName = parseNoLinkTag (GDTag "FONE")$ \(t, children) ->- runMultiMonad children$ PhoneticName- <$> (pure.getPersonalName.gdIgnoreEscapes$ t)- <*> parseRequired (GDTag "TYPE") parsePhoneticType- <*> parseNamePieces---- | Parse a 'RomanizedName'.-parseRomanName :: StructureParser RomanizedName-parseRomanName = parseNoLinkTag (GDTag "FONE")$ \(t, children) ->- runMultiMonad children$ RomanizedName- <$> (pure.getPersonalName.gdIgnoreEscapes$ t)- <*> parseRequired (GDTag "TYPE") parseRomanType- <*> parseNamePieces---- | Parse a 'Sex'.-parseSex :: StructureParser Sex-parseSex = parseNoLinkTag (GDTag "SEX")$ \(t, _) ->- case trim . T.toUpper . gdIgnoreEscapes $ t of- "M" -> return Male- "F" -> return Female- "U" -> return Undetermined- _ -> throwError.FormatError$ "Unknown sex code " <> (T.show t)- --- | Parse a list of 'IndividualAttribute's.-parseIndividualAttribute :: MultiMonad [IndividualAttribute]-parseIndividualAttribute = do- concat <$> mapM (parseMulti.attributeTag) [- (GDTag "CAST", Caste),- (GDTag "DSCR", PhysicalDescription),- (GDTag "EDUC", Education),- (GDTag "IPNO", NationalID),- (GDTag "NATI", NationalOrigin),- (GDTag "NCHI", NChildren . read . T.unpack),- (GDTag "NMR", NMarriages . read . T.unpack),- (GDTag "OCCU", Occupation),- (GDTag "PROP", Possessions),- (GDTag "RELI", Religion),- (GDTag "RESI", const ResidesAt),- (GDTag "SSN", SocialSecurity),- (GDTag "TITL", Title),- (GDTag "FACT", Fact)]- where- attributeTag (tag, mkType) = parseNoLinkTag tag$ \(t, children) ->- runMultiMonad children$ IndividualAttribute (mkType$ gdIgnoreEscapes t)- <$> parseIndividualEventDetail---- | Parse a list of 'IndividualEvent's-parseIndividualEvent :: MultiMonad [IndividualEvent]-parseIndividualEvent = do- famc <- concat <$> mapM (parseMulti.famcTag)- [(GDTag "BIRT", Birth), (GDTag "CHR", Christening)]- adop <- parseMulti.parseNoLinkTag (GDTag "ADOP")$ \(_, children) ->- runMultiMonad children$ IndividualEvent- <$> (Adoption <$> parseOptional parseAdopFamilyRef)- <*> parseIndividualEventDetail- simple <- concat <$> mapM (parseMulti.eventTag) [- (GDTag "DEAT", const Death),- (GDTag "BURI", const Burial),- (GDTag "CREM", const Cremation),- (GDTag "BAPM", const Baptism),- (GDTag "BARM", const BarMitzvah),- (GDTag "BASM", const BasMitzvah),- (GDTag "BLES", const Blessing),- (GDTag "CHRA", const ChristeningAdult),- (GDTag "CONF", const Confirmation),- (GDTag "FCOM", const FirstCommunion),- (GDTag "ORDN", const Ordination),- (GDTag "NATU", const Naturalization),- (GDTag "EMIG", const Emigration),- (GDTag "IMMI", const Immigration),- (GDTag "CENS", const IndvCensus),- (GDTag "PROB", const Probate),- (GDTag "WILL", const Will),- (GDTag "GRAD", const Graduation),- (GDTag "RETI", const Retirement),- (GDTag "EVEN", IndividualEventType)]- return$ famc ++ adop ++ simple- where- eventTag (tag, mkType) = parseNoLinkTag tag$ \(t, children) ->- runMultiMonad children$ IndividualEvent (mkType$ gdIgnoreEscapes t)- <$> parseIndividualEventDetail- famcTag (tag, mkType) = parseNoLinkTag tag$ \(_, children) ->- runMultiMonad children$ IndividualEvent- <$> (mkType <$> parseOptional parseFamilyRef)- <*> parseIndividualEventDetail- parseFamilyRef = parseLinkTag (GDTag "FAMC") - parseAdopFamilyRef = parseTagFull (GDTag "FAMC") nullrref$ \(lb, children) ->- case lb of- Right _ -> throwError.RequiredRef$ "Missing link in FAMC"- Left f -> runMultiMonad children$- AdoptionDetail f <$> parseOptional parseParent- parseParent = parseNoLinkTag (GDTag "ADOP")$ \(t, _) ->- case trim . T.toUpper . gdIgnoreEscapes $ t of- "HUSB" -> return Husband- "WIFE" -> return Wife- "BOTH" -> return BothParents- _ -> throwError.FormatError$ "Invalid parent " <> (T.show t)---- | Parse an 'IndividualEventDetail'.-parseIndividualEventDetail :: MultiMonad IndividualEventDetail-parseIndividualEventDetail = IndividualEventDetail- <$> parseEventDetail- <*> parseOptional (parseWordTag (GDTag "AGE"))---- | Parse a 'ChildToFamilyLink'.-parseChildToFamilyLink :: StructureParser ChildToFamilyLink-parseChildToFamilyLink = parseTagFull (GDTag "FAMC") nullrref$ \(lb, children) ->- case lb of- Right _ -> throwError.RequiredRef$ "Missing link in FAMC"- Left f -> runMultiMonad children$ ChildToFamilyLink f- <$> parseOptional parsePedigree- <*> parseOptional parseChildLinkStatus- <*> parseMulti parseNote---- | Parse a 'Pedigree'.-parsePedigree :: StructureParser Pedigree-parsePedigree = parseNoLinkTag (GDTag "PEDI")$ \(t, _) ->- case trim . T.toUpper . gdIgnoreEscapes$ t of- "ADOPTED" -> return Adopted- "BIRTH" -> return ByBirth- "FOSTER" -> return Foster- "SEALING" -> return Sealing- _ -> throwError.FormatError$ "Invalid pedigree code " <> (T.show t)---- | Parse a 'ChildLinkStatus'.-parseChildLinkStatus :: StructureParser ChildLinkStatus-parseChildLinkStatus = parseNoLinkTag (GDTag "STAT")$ \(t, _) ->- case trim . T.toUpper . gdIgnoreEscapes$ t of- "CHALLENGED" -> return Challenged- "DISPROVEN" -> return Disproved- "PROVEN" -> return Proven- _ -> throwError.FormatError$ "Invalid child link status " <> (T.show t)---- | Parse a 'SpouseToFamilyLink'.-parseSpouseToFamilyLink :: StructureParser SpouseToFamilyLink-parseSpouseToFamilyLink = parseTagFull (GDTag "FAMS") nullrref$- \(lb, children) ->- case lb of- Right _ -> throwError.RequiredRef$ "Missing link in FAMS"- Left f -> runMultiMonad children$ SpouseToFamilyLink f- <$> parseMulti parseNote---- | Parse an 'Association'.-parseAssociation :: StructureParser Association-parseAssociation = parseTagFull (GDTag "ASSO") nullrref$ \(lb, children) ->- case lb of- Right _ -> throwError.RequiredRef$ "Missing link in ASSO"- Left i -> runMultiMonad children$ Association i- <$> parseRequired (GDTag "RELA") (parseTextTag (GDTag "RELA"))- <*> parseMulti parseSourceCitation- <*> parseMulti parseNote---- | Parse a 'SourceRecordedEvent'.-parseSourceRecordedEvent :: StructureParser SourceRecordedEvent-parseSourceRecordedEvent = parseNoLinkTag (GDTag "EVEN")$- \(recorded, children) ->- runMultiMonad children$ SourceRecordedEvent- <$> (pure . catMaybes . fmap getEventType- . T.splitOn "," . gdIgnoreEscapes$ recorded)- <*> parseOptional fullParseDatePeriod- <*> parseOptional (parseListTag (GDTag "PLAC"))- where- fullParseDatePeriod = parseNoLinkTag (GDTag "DATE")$ \(date, _) ->- case parseDatePeriod date of- Just v -> return v- Nothing -> throwError.FormatError$- "Badly formatted date period: " <> (T.show date)---- | Parse a 'RepositoryCitation'.-parseRepositoryCitation :: StructureParser RepositoryCitation-parseRepositoryCitation = parseTagFull (GDTag "REPO") nullrref$- \(lb, children) ->- let repo = case lb of- Left v -> Just v- Right _ -> Nothing- in runMultiMonad children$ RepositoryCitation repo- <$> parseMulti parseNote- <*> parseOptional parseCallNumber---- | Parse a 'CallNumber'.-parseCallNumber :: StructureParser CallNumber-parseCallNumber = parseNoLinkTag (GDTag "CALN")$ \(n, children) ->- runMultiMonad children$ CallNumber (gdIgnoreEscapes n)- <$> parseOptional (parseMultimediaType (GDTag "MEDI"))---- | Parse a 'SourceCitation'.-parseSourceCitation :: StructureParser SourceCitation-parseSourceCitation = parseTagFull (GDTag "SOUR") nullrref$- \(lb, children) ->- case lb of- Left source ->- runMultiMonad children$ SourceCitation (Right source)- <$> parseOptional (parseTextTag (GDTag "PAGE"))- <*> parseMulti parseMultimedia- <*> parseMulti parseNote- <*> parseOptional parseQuality- Right description ->- runMultiMonad children$ SourceCitation- <$> (Left . SourceDescription (gdIgnoreEscapes description)- <$> parseMulti (parseTextTag (GDTag "TEXT")))- <*> pure Nothing- <*> parseMulti parseMultimedia- <*> parseMulti parseNote- <*> parseOptional parseQuality---- | Parse a 'GedcomFormat'.-parseGedcomFormat :: StructureParser GedcomFormat-parseGedcomFormat = parseNoLinkTag (GDTag "GEDC")$ \(_, children) ->- runMultiMonad children$ GedcomFormat- <$> parseRequired (GDTag "VERS") parseVersion- <*> parseRequired (GDTag "FORM") parseGedcomForm---- | Parse a 'GedcomForm'.-parseGedcomForm :: StructureParser GedcomForm-parseGedcomForm = parseNoLinkTag (GDTag "FORM")$ \(t, _) ->- return$ if (T.toUpper . gdIgnoreEscapes$ t) == "LINEAGE-LINKED"- then GedcomLineageLinked- else GedcomUnsupported (gdIgnoreEscapes t)---- | Parse a 'Charset'.-parseCharset :: StructureParser Charset-parseCharset = parseNoLinkTag (GDTag "CHAR")$ \(cs, children) ->- runMultiMonad children$ Charset (gdIgnoreEscapes cs)- <$> parseOptional parseVersion---- | Parse a 'ChangeDate'.-parseChangeDate :: StructureParser ChangeDate-parseChangeDate = parseNoLinkTag (GDTag "CHAN")$ \(_, children) ->- runMultiMonad children$ ChangeDate- <$> parseRequired (GDTag "DATE") parseExactDateTime- <*> parseOptional parseNote---- | Parse 'ContactDetails'.-parseContactDetails :: MultiMonad ContactDetails-parseContactDetails = ContactDetails- <$> parseMulti (parseTextTag (GDTag "PHON"))- <*> parseMulti (parseTextTag (GDTag "EMAIL"))- <*> parseMulti (parseTextTag (GDTag "FAX"))- <*> parseMulti (parseTextTag (GDTag "WWW"))---- | Parse an 'Address'.-parseAddress :: ContactDetails -> StructureParser Address-parseAddress contacts = parseNoLinkTag (GDTag "ADDR")$ \(addr, children) ->- runMultiMonad children$ Address (gdIgnoreEscapes addr)- <$> parseOptional (parseTextTag (GDTag "CITY"))- <*> parseOptional (parseTextTag (GDTag "STAE"))- <*> parseOptional (parseTextTag (GDTag "POS"))- <*> parseOptional (parseTextTag (GDTag "CTRY"))- <*> pure contacts---- | Parse a 'DateValue'.-parseDateValue :: StructureParser DateValue-parseDateValue = parseNoLinkTag (GDTag "DATE")$ \(t, _) ->- let date = (DateApproxV <$> parseDateApprox t)- <|> (DateRangeV <$> parseDateRange t)- <|> (DatePeriodV <$> parseDatePeriod t)- <|> (parseDatePhrase t)- <|> (DateV <$> parseDate t)- in case date of- Just x -> return x- Nothing -> throwError.FormatError$ "Invalid date format " <> (T.show t)---- | Decode a calendar escape sequence to a 'Calendar'.-decodeCalendarEscape :: Maybe GDEscape -> Calendar-decodeCalendarEscape Nothing = Gregorian-decodeCalendarEscape (Just (GDEscape c)) = case T.toUpper c of- "DGREGORIAN" -> Gregorian- "DJULIAN" -> Julian- "DHEBREW" -> Hebrew- "DFRENCH" -> French- "DROMAN" -> Julian- "DUNKNOWN" -> Gregorian- _ -> Gregorian---- | Prepare text for parsing a 'DateValue'.-prepareDateText :: [(Maybe GDEscape, T.Text)] -> [(Maybe GDEscape, T.Text)]-prepareDateText = gdFilterEscapes [- GDEscape "DGREGORIAN",- GDEscape "DJULIAN",- GDEscape "DHEBREW",- GDEscape "DFRENCH",- GDEscape "DROMAN",- GDEscape "DUNKNOWN"]---- | Attempt to extract a 'DatePeriod' from a string with escape sequences.-parseDatePeriod :: [(Maybe GDEscape, T.Text)] -> Maybe DatePeriod-parseDatePeriod t = case prepareDateText t of- ((mCalendarEscape1, t1'):rest) ->- let- calendar1 = decodeCalendarEscape mCalendarEscape1- t1 = trim$ T.toUpper t1'- from = trim <$> T.stripPrefix "FROM" t1- to = trim <$> T.stripPrefix "TO" t1- in case to of- Just r -> DateTo <$> getDate calendar1 r- Nothing -> case from of- Nothing -> Nothing- Just r ->- let topcs = T.splitOn "TO"$ r- in case topcs of- [mfdate, mto] -> DateFrom- <$> getDate calendar1 (trim mfdate)- <*> (pure$ getDate calendar1 (trim mto))- [mfdate] -> case rest of- [] -> DateFrom- <$> getDate calendar1 (trim mfdate) <*> (pure Nothing)- ((mCalendarEscape2, t2'):_) ->- let- calendar2 = decodeCalendarEscape mCalendarEscape2- t2 = trim$ T.toUpper t2'- to2 = trim <$> T.stripPrefix "TO" t2- in case to2 of- Nothing -> Nothing- Just r2 -> DateFrom- <$> getDate calendar1 (trim mfdate)- <*> (pure$ getDate calendar2 (trim r2))- _ -> Nothing- _ -> Nothing---- | Attempt to extract a 'DateRange' from a string with escape sequences.-parseDateRange :: [(Maybe GDEscape, T.Text)] -> Maybe DateRange-parseDateRange t = case prepareDateText t of- ((mCalendarEscape1, t1):rest) ->- let- calendar1 = decodeCalendarEscape mCalendarEscape1- (pref, date1) = second trim . T.splitAt 3 . T.toUpper . trim $ t1- in case pref of- "BEF" -> DateBefore <$> getDate calendar1 date1- "AFT" -> DateAfter <$> getDate calendar1 date1- "BET" -> case T.splitOn "AND" date1 of- [d1, date2'] -> DateBetween- <$> getDate calendar1 d1- <*> getDate calendar1 (trim date2')- [d1] -> case rest of- [] -> Nothing- ((mCalendarEscape2, t2):_) ->- let calendar2 = decodeCalendarEscape mCalendarEscape2- in DateBetween- <$> getDate calendar1 d1- <*> getDate calendar2 (trim t2)- _ -> Nothing- _ -> Nothing- _ -> Nothing---- | Attempt to extract a 'DateApprox' from a string with escape sequences.-parseDateApprox :: [(Maybe GDEscape, T.Text)] -> Maybe DateApprox-parseDateApprox t = case prepareDateText t of- ((mCalendarEscape1, t1):_) ->- let- calendar1 = decodeCalendarEscape mCalendarEscape1- (pref, date) = second trim . T.splitAt 3 . T.toUpper . trim $ t1- cons = case pref of- "ABT" -> Just DateAbout- "CAL" -> Just DateCalculated- "EST" -> Just DateEstimated- _ -> Nothing- in cons <*> getDate calendar1 date- _ -> Nothing---- | Attempt to extract a 'DatePhrase' from a string with escape sequences.-parseDatePhrase :: [(Maybe GDEscape, T.Text)] -> Maybe DateValue-parseDatePhrase t = case prepareDateText t of- ((mCalendarEscape1, t1):_) ->- let- calendar1 = decodeCalendarEscape mCalendarEscape1- int = trim <$> T.stripPrefix "INT" t1- opp = trim <$> T.stripPrefix "(" t1- in case int of- Nothing -> case opp of- Nothing -> Nothing- Just phrase -> Just$- DatePhrase Nothing (trim . T.dropEnd 1$ phrase)- Just rest -> case trim <$> T.splitOn "(" rest of- [date, phrase] -> Just$ - DatePhrase (getDate calendar1 date) (trim . T.dropEnd 1$ phrase)- _ -> Nothing- _ -> Nothing---- | Attempt to extract a 'Date' from a string with escape sequences.-parseDate :: [(Maybe GDEscape, T.Text)] -> Maybe Date-parseDate t = case prepareDateText t of- ((mCalendarEscape, cal):rest) ->- let calendar = decodeCalendarEscape mCalendarEscape- in getDate calendar (cal <> gdIgnoreEscapes rest)- _ -> Nothing---- | Parse a 'Date' from a given string assuming the given 'Calendar'.-getDate :: Calendar -> T.Text -> Maybe Date-getDate calendar = parseMaybe parser- where- yearParser = case calendar of- Gregorian -> yearGreg- _ -> read <$> count' 1 4 digitChar- parseYear = (\y bc -> Year$ if bc then (0 - y) else y)- <$> yearParser <*> ((True <$ string' "B.C.") <|> pure False)- parser :: Parser Date- parser =- (try$ Date calendar- <$> (Just . read <$> count' 1 2 digitChar)- <*> (gdDelim >> (Just <$> parseMonth))- <*> (gdDelim >> parseYear))- <|> (try$ Date calendar Nothing- <$> (gdDelim >> (Just <$> parseMonth))- <*> (gdDelim >> parseYear))- <|> (Date calendar Nothing Nothing- <$> (gdDelim >> parseYear))- parseMonth = case calendar of- Gregorian -> month- Julian -> month- Hebrew -> monthHeb- French -> monthFr- --- | Parse an exact date.-parseExactDate :: StructureParser UTCTime-parseExactDate = parseNoLinkTag (GDTag "DATE")$ \(date, _) ->- case parseMaybe dateExact (gdIgnoreEscapes date) of- Nothing -> throwError.FormatError$ "Bad date \"" <> (T.show date) <> "\""- Just (d, m, y) ->- return$ UTCTime- (fromGregorian (fromIntegral y) (fromIntegral m) d)- (secondsToDiffTime 0)---- | Parse an exact date and time.-parseExactDateTime :: StructureParser UTCTime-parseExactDateTime = parseNoLinkTag (GDTag "DATE")$ \(date, children) -> do- mtime <- runMultiMonad children$ parseOptional (parseTextTag (GDTag "TIME"))-- dt <- case mtime of- Nothing -> return$ secondsToDiffTime 0- Just t -> case parseMaybe timeValue t of- Nothing -> throwError.FormatError$ "Bad time \"" <> (T.show t) <> "\""- Just Nothing -> return$ secondsToDiffTime 0- Just (Just time) -> return$ timeToPicos time-- case parseMaybe dateExact (gdIgnoreEscapes date) of- Nothing -> throwError.FormatError$ "Bad date \"" <> (T.show date) <> "\""- Just (d, m, y) -> return$ UTCTime- (fromGregorian (fromIntegral y) (fromIntegral m) d) dt---- | Parse a 'Multimedia' record.-parseMultimediaRecord :: StructureParser (GDRef Multimedia)-parseMultimediaRecord = parseMultimediaRaw (GDTag "TYPE")---- | Parse a 'Multimedia' link.-parseMultimedia :: StructureParser (GDRef Multimedia)-parseMultimedia = parseMultimediaRaw (GDTag "MEDI")---- | Actual parser for 'Multimedia' values.-parseMultimediaRaw :: GDTag -> StructureParser (GDRef Multimedia)-parseMultimediaRaw typeTag = parseTag (GDTag "OBJE")$ \(_, children) ->- runMultiMonad children$ Multimedia- <$> ((parseOptional (parseMultimediaFormat typeTag)) >>=- (parseMulti.(parseMultimediaFile typeTag)))- <*> parseOptional (parseTextTag (GDTag "TITL"))- <*> parseMulti parseUserReference- <*> parseOptional parseRIN- <*> parseMulti parseNote- <*> parseMulti parseSourceCitation- <*> parseOptional parseChangeDate---- | Parse a 'MultimediaFile'.-parseMultimediaFile ::- GDTag -> Maybe MultimediaFormat ->- StructureParser MultimediaFile-parseMultimediaFile typeTag mf = parseNoLinkTag (GDTag "FILE")$- \(name, children) -> do- (mc, title) <- runMultiMonad children$ (,)- <$> parseOptional (parseMultimediaFormat typeTag)- <*> parseOptional (parseTextTag (GDTag "TITL"))- case mc <|> mf of- Nothing -> throwError.TagError$ "Missing FORM tag for file format"- Just c -> return$ MultimediaFile (gdIgnoreEscapes name) c title---- | Parse a 'MultimediaFormat'.-parseMultimediaFormat :: GDTag -> StructureParser MultimediaFormat-parseMultimediaFormat tag = parseNoLinkTag (GDTag "FORM")$ \(v', children) ->- let v = gdIgnoreEscapes v'- in runMultiMonad children$ MultimediaFormat- (fromMaybe (MF_OTHER v)$ parseMaybe parser v)- <$> parseOptional (parseMultimediaType tag)-- where- parser :: Parser MultimediaFileFormat- parser = (MF_BMP <$ string' "bmp")- <|> (MF_GIF <$ string' "gif")- <|> (MF_JPG <$ string' "jpg")- <|> (MF_OLE <$ string' "ole")- <|> (MF_PCX <$ string' "pcx")- <|> (MF_TIF <$ string' "tif")- <|> (MF_WAV <$ string' "wav")---- | Parse a 'MultimediaType'.-parseMultimediaType :: GDTag -> StructureParser MultimediaType-parseMultimediaType tag = parseNoLinkTag tag$ \(v', _) ->- let v = gdIgnoreEscapes v'- in return.fromMaybe (MT_OTHER v)$ parseMaybe parser v- where- parser :: Parser MultimediaType- parser = (MT_AUDIO <$ string' "audio")- <|> (MT_BOOK <$ string' "book")- <|> (MT_CARD <$ string' "card")- <|> (MT_ELECTRONIC <$ string' "electronic")- <|> (MT_FICHE <$ string' "fiche")- <|> (MT_FILM <$ string' "film")- <|> (MT_MAGAZINE <$ string' "magazine")- <|> (MT_MANUSCRIPT <$ string' "manuscript")- <|> (MT_MAP <$ string' "map")- <|> (MT_NEWSPAPER <$ string' "newspaper")- <|> (MT_PHOTO <$ string' "photo")- <|> (MT_TOMBSTONE <$ string' "tombstone")- <|> (MT_VIDEO <$ string' "video")---- | Parse a 'FamilyEventType'.-getFamilyEventType :: T.Text -> Maybe FamilyEventType-getFamilyEventType = parseMaybe parser- where- parser :: Parser FamilyEventType- parser = (Annuled <$ string' "ANUL")- <|> (FamCensus <$ string' "CENS")- <|> (Divorce <$ string' "DIV")- <|> (DivorceFiled <$ string' "DIVF")- <|> (Engagement <$ string' "ENGA")- <|> (MarriageBann <$ string' "MARB")- <|> (MarriageContract <$ string' "MARC")- <|> (Marriage <$ string' "MARR")- <|> (MarriageLicense <$ string' "MARL")- <|> (MarriageSettlement <$ string' "MARS")- <|> (Residence <$ string' "RESI")- <|> (FamilyEventType . T.pack <$>- (string' "EVEN" *> gdDelim *> many anyChar))---- | Parse an 'IndividualEventType'.-getIndividualEventType :: T.Text -> Maybe IndividualEventType-getIndividualEventType = parseMaybe parser- where- parser :: Parser IndividualEventType- parser = (Birth Nothing <$ (string' "BIRTH"- *> optional (gdDelim >> string' "Y")))- <|> (Christening Nothing <$ (string' "CHR"- *> optional (gdDelim >> string' "Y")))- <|> (Death <$ (string' "DEAT"- *> optional (gdDelim >> string' "Y")))- <|> (Burial <$ string' "BURI")- <|> (Cremation <$ string' "CREM")- <|> (Adoption Nothing <$ string' "ADOP")- <|> (Baptism <$ string' "BAPM")- <|> (BarMitzvah <$ string' "BARM")- <|> (BasMitzvah <$ string' "BASM")- <|> (Blessing <$ string' "BLES")- <|> (ChristeningAdult <$ string' "CHRA")- <|> (Confirmation <$ string' "CONF")- <|> (FirstCommunion <$ string' "FCOM")- <|> (Ordination <$ string' "ORDN")- <|> (Naturalization <$ string' "NATU")- <|> (Emigration <$ string' "EMIG")- <|> (Immigration <$ string' "IMMI")- <|> (IndvCensus <$ string' "CENS")- <|> (Probate <$ string' "PROB")- <|> (Will <$ string' "WILL")- <|> (Graduation <$ string' "GRAD")- <|> (Retirement <$ string' "RETI")- <|> (IndividualEventType . T.pack <$>- (string' "EVEN" *> gdDelim *> many anyChar))---- | Parse an 'EventType'.-getEventType :: T.Text -> Maybe EventType-getEventType et =- let- t = trim$ T.toUpper et- fam = getFamilyEventType et- indv = getIndividualEventType et- in- if t == "CENS" then Just Census- else if (T.take 4 t) == "EVEN" then- Just . EventType . trim . T.drop 4$ et- else fmap FamilyEventTypeV fam <|> fmap IndividualEventTypeV indv---- | Parse a place form structure.-parsePlaceForm :: StructureParser [T.Text]-parsePlaceForm = parseNoLinkTag (GDTag "PLAC")$ \(_, children) ->- runMultiMonad children$ fromMaybe [].(fmap$ T.splitOn ",") <$>- parseOptional (parseTextTag (GDTag "FORM"))---- | Parse a 'UserReference'.-parseUserReference :: StructureParser UserReference-parseUserReference = parseNoLinkTag (GDTag "REFN")$ \(i, children) ->- runMultiMonad children$ UserReference (gdIgnoreEscapes i)- <$> parseOptional (parseTextTag (GDTag "TYPE"))---- | Parse a version structure.-parseVersion :: StructureParser T.Text-parseVersion = parseTextTag (GDTag "VERS")---- | Parse a NAME tag.-parseName :: StructureParser T.Text-parseName = parseTextTag (GDTag "NAME")---- | Parse a copyright tag.-parseCopyright :: StructureParser T.Text-parseCopyright = parseTextTag (GDTag "COPR")---- | Parse a file name.-parseFile :: StructureParser FilePath-parseFile = (fmap.fmap.fmap) T.unpack$ parseTextTag (GDTag "FILE")---- | Parse an 'AFN'.-parseAFN :: StructureParser AFN-parseAFN = (fmap.fmap.fmap) AFN$ parseTextTag (GDTag "AFN")---- | Parse a 'RFN'.-parseRFN :: StructureParser RFN-parseRFN = (fmap.fmap.fmap) RFN$ parseTextTag (GDTag "RFN")---- | Parse a 'RIN'.-parseRIN :: StructureParser RIN-parseRIN = (fmap.fmap.fmap) RIN$ parseTextTag (GDTag "RIN")---- | Parse a 'Language'.-parseLanguage :: StructureParser Language-parseLanguage = (fmap.fmap.fmap) (Language) $ parseTextTag (GDTag "LANG")---- | Parse a 'QualityAssessment'.-parseQuality :: StructureParser QualityAssessment-parseQuality = (fmap.fmap.fmap) QualityAssessment $ parseWordTag (GDTag "QUAY")---- | Parse a boolean value.-parseBoolTag :: GDTag -> StructureParser Bool-parseBoolTag tag = parseNoLinkTag tag$ \(v, _) ->- case parseMaybe ynParser (gdIgnoreEscapes v) of- Nothing -> throwError.FormatError$ "Expected boolean, saw " <> (T.show v)- Just yn -> return yn- where- ynParser :: Parser Bool- ynParser = (True <$ string' "yes") <|> (False <$ string' "no")---- | Parse a Word value.-parseWordTag :: GDTag -> StructureParser Word-parseWordTag tag = parseNoLinkTag tag$ \(v, _) ->- case parseMaybe parser (gdIgnoreEscapes v) of- Nothing -> throwError.FormatError$ "Expected number, saw " <> (T.show v)- Just n -> return . read $ n- where- parser :: Parser String- parser = many digitChar---- | Extract the text from a tag.-parseTextTag :: GDTag -> StructureParser T.Text-parseTextTag tag = parseNoLinkTag tag (return.gdIgnoreEscapes.fst)---- | Extract a list of comma separated values from a tag.-parseListTag :: GDTag -> StructureParser [T.Text]-parseListTag tag =- parseNoLinkTag tag (return . T.splitOn "," . gdIgnoreEscapes . fst)---- | Handler for tags that cannot contain cross references.-type NoLinkHandler a =- ([(Maybe GDEscape, T.Text)], [GDTree]) -> StructureMonad a---- | Handler for general tags.-type TagHandler b a =- (Either (GDRef b) [(Maybe GDEscape, T.Text)], [GDTree])- -> StructureMonad a---- | A function that adds references to the cross reference table.-type RegisterRef a = GDTag -> GDXRefID -> a -> StructureMonad ()---- | Don't add any references.-nullrref :: Typeable a => RegisterRef a-nullrref _ _ _ = return ()---- | Add direct references only.-defrref :: Typeable a => RegisterRef (GDRef a)-defrref _ thisID (GDStructure a) = addReference thisID a-defrref tag _ _ = throwError.UnexpectedRef$- "Referenced structure references another structure " <> (T.show tag)---- | Parse a tag which is either a GEDCOM structure, or a reference to the--- expected GEDCOM structure.-parseTag :: Typeable a- => GDTag -- ^ The tag to parse.- -> NoLinkHandler a -- ^ A handler for the tag- -> StructureParser (GDRef a)-parseTag tag handler = parseTagFull tag defrref$ \(lb, children) ->- case lb of- Left ref -> return ref- Right text -> GDStructure <$> handler (text, children)---- | Parse a tag which cannot contain a cross reference (i.e. the tag must--- contain the structure itself, not a reference to another structure).-parseNoLinkTag :: Typeable a- => GDTag -- ^ The tag to parse.- -> NoLinkHandler a -- ^ A handler for the tag.- -> StructureParser a-parseNoLinkTag tag handler = parseTagFull tag nullrref$ \(lb, children) ->- case lb of- Left _ -> throwError.UnexpectedRef$- "Cannot follow cross references on " <> (T.show tag)- Right text -> handler (text, children)---- | Parse a tag which must contain a cross reference to another structure, not--- the structure itself.-parseLinkTag :: Typeable a => GDTag -> StructureParser (GDRef a)-parseLinkTag tag = parseTagFull tag nullrref$ \(lb, _) ->- case lb of- Left ref -> return ref- Right _ -> throwError.RequiredRef$- "Expected cross reference was missing in " <> (T.show tag)---- | The most general tag parsing function.-parseTagFull :: Typeable a- => GDTag -- ^ The tag to parse.- -> RegisterRef a -- ^ How to register cross references.- -> TagHandler b a -- ^ How to convert the tag into a GEDCOM structure.- -> StructureParser a-parseTagFull tag rref handler t@(GDTree (GDLine _ mthisID tag' v) children) =- if tag /= tag' then return$ Left t else do- r <- case v of- Nothing -> Right <$> (handler.(first Right)$ parseCont mempty children)- Just (GDXRefIDV xref) -> do- Right <$> (handler (Left (GDXRef xref), children))- Just (GDLineItemV l1) ->- Right <$> (handler.(first Right)$ parseCont l1 children)- case (mthisID, r) of- (Just thisID, Right rv) -> rref tag thisID rv- _ -> return ()- return r---- | Handle CONT and CONC tags.-parseCont ::- GDLineItem -- ^ The value of the first line- -> [GDTree] -- ^ The sub tree- -> ([(Maybe GDEscape, T.Text)], [GDTree]) -- ^ The concatenation of the values of all the CONT and CONC tags, and the remaining tags.-parseCont l1 children =- bimap assemble (fmap snd).span (isJust.fst)$- zipWith (\l r -> (cont l <|> conc l, r)) children children- where- assemble = gdLineData . mconcat . (l1:) . catMaybes . fmap fst- cont (GDTree (GDLine _ _ (GDTag "CONT") (Just (GDLineItemV l))) _) =- Just$ GDLineItem [(Nothing, "\r\n")] <> l- cont _ = Nothing- conc (GDTree (GDLine _ _ (GDTag "CONC") (Just (GDLineItemV l))) _) =- Just$ gdTrimLineItem l- conc _ = Nothing-
src/Data/Gedcom/Structure.hs view
@@ -96,7 +96,7 @@ Year (..) ) where -import Data.Gedcom.Common+import Data.Gedcom.Internal.CoreTypes import Data.Time.Clock import qualified Data.Text.All as T
test/Spec.hs view
@@ -1,2 +1,153 @@+{-# LANGUAGE OverloadedStrings #-}++import Data.Gedcom.Internal.CoreTypes+import Data.Gedcom.Internal.LineParser+import Data.Gedcom.Internal.ParseMonads+import Data.Gedcom.Internal.Parser+import Data.Monoid+import Data.Void+import qualified Data.Text.All as T+import Test.Hspec+import Text.Megaparsec++testTagData :: T.Text+testTagData = "some test data"++testTag :: T.Text -> Maybe GDLine+testTag d = do+ (GDRoot [GDTree t []]) <- parseMaybe gdRoot$ "0 TEST " <> d <> "\n"+ return t++emptyTag :: Maybe GDLine+emptyTag = do+ (GDRoot [GDTree t []]) <- parseMaybe gdRoot$ "0 TEST\n"+ return t++ref1 :: GDXRefID+ref1 = GDXRefID "1"++linkTag :: Maybe GDLine+linkTag = do+ (GDRoot [GDTree t []]) <- parseMaybe gdRoot$ "0 TEST @1@\n"+ return t++linkLinkTag :: Maybe GDLine+linkLinkTag = do+ (GDRoot [GDTree t []]) <- parseMaybe gdRoot$ "0 @2@ TEST @1@\n"+ return t++crdTag :: Maybe GDLine+crdTag = do+ (GDRoot [GDTree t []]) <-+ parseMaybe gdRoot$ "0 @1@ TEST " <> testTagData <> "\n"+ return t++data ParseReturn a =+ Error T.Text | NoMatch | Match a deriving (Show, Eq)++isError :: ParseReturn a -> Bool+isError (Error _) = True+isError _ = False++parseStructure :: Maybe GDTree -> StructureParser a -> ParseReturn a+parseStructure Nothing p = Error "Line parse error"+parseStructure (Just v) p = case runStructure (p v) of+ (Right (Left _), _) -> NoMatch+ (Right (Right m), _) -> Match m+ (Left err, _) -> Error$ T.show err++noEscapes :: T.Text -> [(Maybe GDEscape, T.Text)]+noEscapes v = [(Nothing, v)]+ main :: IO ()-main = putStrLn "Test suite not yet implemented"+main = hspec$ do+ describe "gdRoot"$ do+ it "parses a simple line with no children"$+ (testTag testTagData) `shouldBe`+ (Just$ GDLine (GDLevel 0) Nothing (GDTag "TEST")+ (Just . GDLineItemV . GDLineItem . noEscapes$ testTagData))+ it "parses a simple cross referenced line"$+ crdTag `shouldBe` (Just$ GDLine (GDLevel 0) (Just ref1) (GDTag "TEST")+ (Just . GDLineItemV . GDLineItem . noEscapes$ testTagData))+ it "parses a simple line cross referencing line"$+ linkTag `shouldBe` (Just$ GDLine (GDLevel 0) Nothing (GDTag "TEST")+ (Just . GDXRefIDV$ ref1))+ it "parses an empty tag with no children"$+ emptyTag `shouldBe`+ (Just$ GDLine (GDLevel 0) Nothing (GDTag "TEST") Nothing)++ describe "parseNoLinkTag"$ do+ it "matches the specified tag"$+ testLine (testTag testTagData) (parseNoLinkTag (GDTag "TEST") pure)+ `shouldBe` (Match (noEscapes testTagData, []))+ it "matches the specified tag (with a cross reference)" $+ testLine crdTag (parseNoLinkTag (GDTag "TEST") pure)+ `shouldBe` (Match (noEscapes testTagData, []))+ it "doesn't match other tags"$+ testLine (testTag testTagData) (parseNoLinkTag (GDTag "OTHER") pure)+ `shouldBe` NoMatch+ it "doesn't parse links"$+ isError$ testLine linkTag (parseNoLinkTag (GDTag "TEST") pure)++ describe "parseTag"$ do+ it "matches the specified tag"$+ testLine (testTag testTagData) (parseTag (GDTag "TEST") pure)+ `shouldBe` (Match . GDStructure$ (noEscapes testTagData, []))+ it "matches the specified tag (with a cross reference)" $+ testLine crdTag (parseTag (GDTag "TEST") pure)+ `shouldBe` (Match . GDStructure$ (noEscapes testTagData, []))+ it "doesn't match other tags"$+ testLine (testTag testTagData) (parseTag (GDTag "OTHER") pure)+ `shouldBe` NoMatch+ it "parses links"$+ testLine linkTag (parseTag (GDTag "TEST") pure)+ `shouldBe` (Match$ GDXRef ref1)+ it "doesn't parse links to links"$+ isError$ testLine linkLinkTag (parseTag (GDTag "TEST") pure)++ describe "parseLinkTag"$ do+ it "parses link tags"$+ testLine linkTag (parseLinkTag (GDTag "TEST")) `shouldBe`+ (Match$ (GDXRef ref1 :: GDRef Void))+ it "doesn't parse other tags"$+ isError$ testLine (testTag testTagData)+ (parseLinkTag (GDTag "TEST") :: StructureParser (GDRef Void))++ describe "parseTextTag"$ do+ it "matches the specified tag" $+ testLine (testTag testTagData) (parseTextTag (GDTag "TEST"))+ `shouldBe` (Match testTagData)++ describe "parseListTag"$ do+ it "splits lists"$+ testLine (testTag "one,,two,three,four") (parseListTag (GDTag "TEST"))+ `shouldBe` (Match ["one", "", "two", "three", "four"])+ it "handles the empty list"$+ testLine emptyTag (parseListTag (GDTag "TEST")) `shouldBe` (Match [])++ describe "parseWordTag"$ do+ it "parses numbers"$+ testLine (testTag "42") (parseWordTag (GDTag "TEST")) `shouldBe` (Match 42)+ it "doesn't parse negative numbers"$+ isError$ testLine (testTag "-42") (parseWordTag (GDTag "TEST"))+ it "doesn't parse empty strings"$+ isError$ testLine (testTag "") (parseWordTag (GDTag "TEST"))++ describe "parseBoolTag"$ do+ it "parses yes and no"$ do+ testLine (testTag "yes") (parseBoolTag (GDTag "TEST"))+ `shouldBe` (Match True)+ testLine (testTag "no") (parseBoolTag (GDTag "TEST"))+ `shouldBe` (Match False)+ it "parses case insensitive"$ do+ testLine (testTag "Yes") (parseBoolTag (GDTag "TEST"))+ `shouldBe` (Match True)+ testLine (testTag "nO") (parseBoolTag (GDTag "TEST"))+ `shouldBe` (Match False)+ it "doesn't parse anything else"$+ (isError$ testLine (testTag "true") (parseBoolTag (GDTag "TEST")))+ && (isError$ testLine (testTag "false") (parseBoolTag (GDTag "TEST")))++ where+ testLine l = parseStructure (GDTree <$> l <*> pure [])+