-- ResMlt.gf: Language-specific parameter types, morphology, VP formation -- -- Maltese GF Resource Grammar -- John J. Camilleri 2011 -- 2013 -- Angelo Zammit 2012 -- Licensed under LGPL --# -path=.:../abstract:../common:../prelude resource ResMlt = ParamX ** open Prelude, Predef, Maybe in { flags coding=utf8 ; optimize=noexpand ; {- General -------------------------------------------------------------- -} param Gender = Masc | Fem ; GenNum = GSg Gender -- DAK, DIK | GPl -- DAWK ; Definiteness = Definite -- eg BIL- | Indefinite -- eg BI ; oper bool2definiteness : Bool -> Definiteness = \b -> if_then_else Definiteness b Definite Indefinite ; -- Agreement system corrected based on comments by [AZ] Agr : Type = { n : Number ; p : Person ; g : Gender } ; -- Make Agr from raw ingredients mkAgr : Number -> Person -> Gender -> Agr = \n,p,g -> {n = n ; p = p ; g = g} ; -- Convert to Agr from other typek toAgr = overload { toAgr : GenNum -> Agr = \gn -> case gn of { GSg g => {n = Sg ; p = P3 ; g = g} ; GPl => {n = Pl ; p = P3 ; g = Masc} } ; toAgr : VAgr -> Agr = \vagr -> case vagr of { AgP1 num => mkAgr num P1 Masc ; AgP2 num => mkAgr num P2 Masc ; AgP3Sg gen => mkAgr Sg P3 gen ; AgP3Pl => mkAgr Pl P3 Masc } ; } ; -- Make Agr from raw ingredients mkGenNum = overload { mkGenNum : Gender -> Number -> GenNum = \g,n -> case n of { Sg => GSg g ; Pl => GPl } ; mkGenNum : Number -> Gender -> GenNum = \n,g -> case n of { Sg => GSg g ; Pl => GPl } ; mkGenNum : Noun_Number -> Gender -> GenNum = \n,g -> case nounnum2num n of { Sg => GSg g ; Pl => GPl } ; } ; -- Convert to GenNum from another type toGenNum : Agr -> GenNum = \a -> case a.n of { Sg => GSg a.g ; Pl => GPl } ; -- Convert to VAgr from another type toVAgr = overload { toVAgr : Agr -> VAgr = \agr -> case of { => AgP1 num; => AgP2 num; => AgP3Sg agr.g; => AgP3Pl } ; toVAgr : GenNum -> VAgr = \gn -> case gn of { GSg g => AgP3Sg g; GPl => AgP3Pl } ; } ; agrP3 : Number -> Gender -> Agr = \n,g -> mkAgr n P3 g; sing : VAgr -> Bool = \agr -> case toAgr agr of { {n=Sg; p=_; g=_} => True ; _ => False } ; femOrPlural : Agr -> Bool = \agr -> case agr of { {n=Sg; p=_; g=Fem} => True ; {n=Pl; p=_; g=_} => True ; _ => False } ; conjAgr : Agr -> Agr -> Agr = \a,b -> { n = (conjNumber a.n b.n) ; p = (conjPerson a.p b.p) ; g = a.g ; } ; -- ConjNumber, ConjPerson are defined in ParamX conjGender : Gender -> Gender -> Gender = \a,b -> b ; param -- Agreement for verbs VAgr = AgP1 Number -- JIENA, AĦNA | AgP2 Number -- INTI, INTOM | AgP3Sg Gender -- HUWA, HIJA | AgP3Pl -- HUMA ; param NPCase = NPNom | NPAcc -- I have a feeling we'll this need eventually | NPCPrep -- [AZ] ; oper npNom = NPNom ; npAcc = NPAcc ; {- Clause --------------------------------------------------------------- -} oper Clause : Type = { s : Tense => Anteriority => Polarity => Order => Str } ; QClause : Type = { s : Tense => Anteriority => Polarity => QForm => Str } ; RClause : Type = { s : Tense => Anteriority => Polarity => Agr => Str } ; mkClause : Str -> Agr -> VerbPhrase -> Clause = \subj,agr,vp -> { s = \\tense,ant,pol,ord => let verb : Str = joinVP vp tense ant pol agr ; obj : Str = vp.s2 ! agr ; in case ord of { ODir => subj ++ verb ++ obj ; -- Ġanni jiekol ħut OQuest => verb ++ obj ++ subj -- jiekol ħut Ġanni ? } } ; mkQuestion : {s : Str} -> Clause -> QClause = \wh,cl -> { s = \\t,a,p => let cls = cl.s ! t ! a ! p ; why = wh.s in table { QDir => why ++ cls ! OQuest ; QIndir => why ++ cls ! ODir } } ; {- Numeral -------------------------------------------------------------- -} param CardOrd = NCard | NOrd ; -- Order of magnitude DForm = Unit -- 0..10 | Teen -- 11..19 | Ten -- 20..99 | Hund -- 100..999 | Thou -- 1000+ ; -- Indicate how a corresponding object should be treated -- Num Sg is exactly 1 -- Num1 is anything "treated as" 1 (eg 101) NumForm = NumX Number -- Sg | Pl | Num0 -- 0 (l-edba SIEGĦA) | Num1 -- 101... (mija u SIEGĦA) | Num2 -- 2 (SAGĦTEJN) | Num3_10 -- 3..10, 102, 103... (tlett SIEGĦAT, għaxar SIEGĦAT, mija u żewġ SIEGĦAT, mija u tlett SIEGĦAT) | Num11_19 -- 11..19, 111... (ħdax-il SIEGĦA, mija u dsatax-il SIEGĦA) | Num20_99 -- 20..99, 120... (għoxrin SIEGĦA, disa' u disgħajn SIEGĦA) ; NumCase = NumNom -- "Type B" in {MDG, 133}, e.g. TNEJN, ĦAMSA, TNAX, MIJA | NumAdj -- "Type A" in {MDG, 133}, e.g. ŻEWĠ, ĦAMES, TNAX-IL, MITT ; oper num2nounnum : Number -> Noun_Number = \n -> case n of { Sg => Singulative ; Pl => Plural } ; nounnum2num : Noun_Number -> Number = \n -> case n of { Singulative => Sg ; Collective => Sg ; Dual => Pl ; Plural => Pl } ; numform2nounnum : NumForm -> Noun_Number = \n -> case n of { NumX Sg => Singulative ; NumX Pl => Plural ; Num0 => Singulative ; Num1 => Singulative ; Num2 => Dual ; Num3_10 => Collective ; Num11_19 => Singulative ; Num20_99 => Plural } ; numform2num : NumForm -> Number = \n -> case n of { NumX num => num ; Num0 => Sg ; Num1 => Sg ; _ => Pl } ; {- Determiners etc. ----------------------------------------------------- -} oper Determiner : Type = { s : Gender => Str ; n : NumForm ; clitic : Str ; hasNum : Bool ; -- has a numeral isPron : Bool ; -- is a pronoun isDefn : Bool ; -- is definite } ; Quantifier : Type = { s : GenNum => Str ; clitic : Str ; isPron : Bool ; isDemo : Bool ; -- Demonstrative (this/that/those/these) isDefn : Bool ; -- is definite } ; {- Noun ----------------------------------------------------------------- -} oper Noun : Type = { s : Noun_Number => Str ; g : Gender ; hasColl : Bool ; -- has a collective form? e.g. BAQAR hasDual : Bool ; -- has a dual form? e.g. SAGĦTEJN takesPron : Bool ; -- takes enclitic pronon? e.g. MISSIERI } ; ProperNoun : Type = { s : Str ; a : Agr ; -- ignore a.p (always P3) } ; NounPhrase : Type = { s : NPCase => Str ; a : Agr ; isPron : Bool ; isDefn : Bool ; } ; param Noun_Number = Singulative -- ĦUTA | Collective -- ĦUT | Dual -- WIDNEJN | Plural -- ĦUTIET ; oper -- Noun: Takes all forms and a gender -- Params: -- Singulative, eg KOXXA -- Collective, eg KOXXOX -- Double, eg KOXXTEJN -- Determinate Plural, eg KOXXIET -- Indeterminate Plural -- Gender mkNoun : (_,_,_,_,_ : Str) -> Gender -> (_,_ : Bool) -> Noun = \sing,coll,dual,det,ind,gen,hasColl,hasDual -> { s = table { Singulative => sing ; Collective => coll ; Dual => dual ; Plural => det -- Plural => variants {det ; ind} } ; g = gen ; takesPron = False ; hasDual = hasDual ; hasColl = hasColl ; } ; -- Noun phrase mkNP : Str -> Number -> Person -> Gender -> NounPhrase = \s,n,p,g -> { s = \\npcase => s ; a = mkAgr n p g ; isPron = False ; isDefn = False ; }; regNP : Str -> NounPhrase = \kulhadd -> mkNP kulhadd Sg P3 Masc ; -- kulħadd kuntent -- Join a preposition and NP to a string prepNP : Preposition -> NounPhrase -> Str ; prepNP prep np = case np.isPron of { True => prep.enclitic ! np.a ; -- magħha False => case of { => prep.s ! Definite ++ np.s ! NPCPrep ; -- fit-triq => prep.s ! Definite ++ np.s ! NPNom ; -- fuq it-triq => prep.s ! Indefinite ++ np.s ! NPNom -- fi triq } } ; Compl : Type = Preposition ** {isPresent : Bool} ; noCompl : Compl = { s = \\_ => [] ; enclitic = \\_ => [] ; takesDet = False ; joinsVerb = False ; isPresent = False ; } ; {- Preposition ---------------------------------------------------------- -} Preposition = { s : Definiteness => Str ; enclitic : Agr => Str ; -- when suffixed by pronouns; magħ-ha takesDet : Bool ; -- True: fil- / False: fuq il- joinsVerb : Bool ; -- True for for_Prep (I.O. suffix) } ; prep_ta : Preposition = { s = table { Indefinite => "ta'" ; Definite => makePreFull "tal-" "ta" "t'" } ; enclitic : Agr => Str = \\agr => case toVAgr agr of { AgP1 Sg => "tiegħi" ; AgP2 Sg => "tiegħek" ; AgP3Sg Masc => "tiegħu" ; AgP3Sg Fem => "tagħha" ; AgP1 Pl => "tagħna" ; AgP2 Pl => "tagħkom" ; AgP2Pl => "tagħhom" } ; takesDet = True ; joinsVerb = False ; } ; prep_minn : Preposition = { s = table { Indefinite => "minn" ; Definite => makePreFull "mill-" "mi" "m" } ; enclitic : Agr => Str = \\agr => case toVAgr agr of { AgP1 Sg => "minni" ; AgP2 Sg => "minnek" ; AgP3Sg Masc => "minnu" ; AgP3Sg Fem => "minnha" ; AgP1 Pl => "minna" ; AgP2 Pl => "minnkom" ; AgP2Pl => "minnhom" } ; takesDet = True ; joinsVerb = False ; } ; prep_lil : Preposition = { s = table { Indefinite => "lil" ; Definite => makePreFull "lill-" "lil" "lil" } ; enclitic : Agr => Str = \\agr => case toVAgr agr of { AgP1 Sg => "lili" ; AgP2 Sg => "lilek" ; AgP3Sg Masc => "lilu" ; AgP3Sg Fem => "lilha" ; AgP1 Pl => "lilna" ; AgP2 Pl => "lilkom" ; AgP2Pl => "lilhom" } ; takesDet = True ; joinsVerb = True ; } ; {- Pronoun -------------------------------------------------------------- -} oper Pronoun = { s : PronForm => Str ; -- cases like omm-i / hi-ja are handled elsewhere a : Agr ; } ; param PronForm = Personal -- jiena | Possessive -- tiegħi | Suffixed -- qalb-i Only nouns! -- | Suffixed PronCase ; -- PronCase = -- Acc -- Accusative: rajtu -- | Dat -- Dative: rajtlu -- | Gen -- Genitive: qalbu -- ; oper -- Interrogative pronoun mkIP : Str -> Number -> {s : Str ; n : Number} = \who,n -> { s = who ; n = n } ; {- Verb ----------------------------------------------------------------- -} oper -- Stem variants VerbStems : Type = {s1, s2, s3 : Str} ; mkVerbStems : VerbStems = overload { mkVerbStems : (s1 : Str) -> VerbStems = \a -> { s1 = a ; s2 = a ; s3 = a } ; mkVerbStems : (s1, s2 : Str) -> VerbStems = \a,b -> { s1 = a ; s2 = b ; s3 = b } ; mkVerbStems : (s1, s2, s3 : Str) -> VerbStems = \a,b,c -> { s1 = a ; s2 = b ; s3 = c } ; } ; NullAgr : Maybe Agr = Nothing Agr (agrP3 Sg Masc) ; -- Direct object clitic DirObjVerbClitic : Type = { s1 : Str ; s2 : Str ; s3 : Str ; } ; dirObjSuffix : Agr -> DirObjVerbClitic = \agr' -> let agr : VAgr = toVAgr agr' in case agr of { -- DO DO + .. DO + .. (Neg) AgP1 Sg => { s1="ni" ; s2="ni" ; s3="ni" } ; AgP2 Sg => { s1="ek" ; s2="ek" ; s3="k" } ; AgP3Sg Masc => { s1="u" ; s2="hu" ; s3="hu" } ; AgP3Sg Fem => { s1="ha" ; s2="hie" ; s3="hi" } ; AgP1 Pl => { s1="na" ; s2="nie" ; s3="hi" } ; AgP2 Pl => { s1="kom" ; s2="kom" ; s3="kom" } ; AgP3Pl => { s1="hom" ; s2="hom" ; s3="hom" } } ; -- Indirect object clitic IndObjVerbClitic : Type = { s1 : Str ; -- ftaħt-ilha s2 : Str ; -- ftaħnie-lha s3 : Str ; -- ftaħt-ilhiex s4 : Str ; -- ftaħnie-lhiex } ; -- Only for_Prep causes these to be used, thus it doesn't make sense to store this -- information in Prep. indObjSuffix : Agr -> IndObjVerbClitic = \agr' -> let agr : VAgr = toVAgr agr' in case agr of { -- IO IO + Neg IO IO + Neg AgP1 Sg => { s1="li" ; s2="li" ; s3="li" ; s4="li" } ; AgP2 Sg => { s1="lek" ; s2="lek" ; s3="lok" ; s4="lok" } ; AgP3Sg Masc => { s1="lu" ; s2="lu" ; s3="lu" ; s4="lu" } ; AgP3Sg Fem => { s1="lha" ; s2="lhie" ; s3="ilha" ; s4="ilhie" } ; AgP1 Pl => { s1="lna" ; s2="lnie" ; s3="ilna" ; s4="ilnie" } ; AgP2 Pl => { s1="lkom" ; s2="lkom" ; s3="ilkom" ; s4="ilkom" } ; AgP3Pl => { s1="lhom" ; s2="lhom" ; s3="ilhom" ; s4="ilhom" } } ; -- Produce stem variants as needed (only call on compile-time strings!) -- Refer to doc/stems.org stemVariantsPerf : Str -> VerbStems = \s -> let ftahna : Str = s ; ftahnie : Str = case s of { ftahn + "a" => ftahn + "ie" ; fet + h@#Cns + "et" => fet + h + "it" ; fet + "aħ" => fet + "ħ" ; qat + "a'" => qat + "a" ; -- waqa' -> ma waqax _ => s } ; ftahni : Str = case s of { ftahn + "a" => ftahn + "i" ; qat + "a'" => qat + "agħ" ; _ => ftahnie } ; in { s1 = ftahna ; s2 = ftahnie ; s3 = ftahni ; } ; stemVariantsImpf : Str -> VerbStems = \s -> let jiftah : Str = s ; jifth : Str = case s of { jift + "aħ" => jift + "ħ" ; jaq + "a'" => jaq + "a" ; -- jaqa' -> ma jaqax _ => s } ; jaqagh : Str = case s of { jaq + "a'" => jaq + "agħ" ; _ => jifth } ; in { s1 = jiftah ; s2 = jifth ; s3 = jaqagh ; } ; -- Convert old verb form table into one with stem variants stemVariantsTbl : (VForm => Str) -> (VForm => VerbStems) = \tbl -> \\vf => case vf of { VPerf _ => stemVariantsPerf (tbl ! vf) ; VImpf _ => stemVariantsImpf (tbl ! vf) ; VImp _ => stemVariantsImpf (tbl ! vf) } ; Verb : Type = { s : VForm => VerbStems ; --- need to store different "stems" already at verb level (ġera/ġerie/ġeri) i : VerbInfo ; presPart : Maybe Participle ; pastPart : Maybe Participle ; } ; Participle : Type = GenNum => Str ; noParticiple : Maybe Participle = Nothing Participle (\\_ => nonExist) ; VerbInfo : Type = { class : VClass ; form : VDerivedForm ; root : Root ; -- radicals vseq : Vowels ; -- vowels extracted from mamma imp : Str ; -- Imperative Sg. Gives so much information jaħasra! } ; param VForm = VPerf VAgr -- Perfect tense in all pronoun cases | VImpf VAgr -- Imperfect tense in all pronoun cases | VImp Number -- Imperative is always P2, Sg & Pl ; VDerivedForm = FormI | FormII | FormIII | FormIV | FormV | FormVI | FormVII | FormVIII | FormIX | FormX | FormUnknown ; -- Verb classification VClass = Strong VStrongClass | Weak VWeakClass | Quad VQuadClass | Loan | Irregular ; VStrongClass = Regular | LiquidMedial | Geminated ; VWeakClass = Assimilative | Hollow | Lacking | Defective ; VQuadClass = QStrong | QWeak ; Order = ODir -- ĠANNI JIEKOL ĦUT | OQuest -- JIEKOL ĦUT ĠANNI [?] ; {- Verb Phrase ---------------------------------------------------------- -} oper -- Pick the correct form of a verb, adding aux pickVerbForm : {s : VForm => VerbStems} -> Tense -> Anteriority -> Polarity -> Agr -> VerbParts = \verb,tense,ant,pol,agr -> let vagr : VAgr = toVAgr agr ; ma = makePreVowel "ma" "m'" ; b1 : VerbStems -> VerbParts = \vs -> mkVerbParts vs ; b2 : Str -> VerbStems -> VerbParts = \s,vs -> mkVerbParts s vs ; kien = copula_kien.s ! (VPerf vagr) ! Pos ; kienx = copula_kien.s ! (VPerf vagr) ! Neg ; nkun = copula_kien.s ! (VImpf vagr) ! Pos ; in case of { => b1 (verb.s ! VImpf vagr) ; -- norqod => b2 ma (verb.s ! VImpf vagr) ; -- ma norqodx => b1 (verb.s ! VPerf vagr) ; -- rqadt => b2 ma (verb.s ! VPerf vagr) ; -- ma rqadtx => b2 "se" (verb.s ! VImpf vagr) ; -- se norqod => b2 (mhux ! vagr ++ "se") (verb.s ! VImpf vagr) ; -- m'iniex se norqod => b2 kien (verb.s ! VImpf vagr) ; -- kont norqod => b2 (ma ++ kienx) (verb.s ! VImpf vagr) ; -- ma kontx norqod -- Same as Past Simul => b1 (verb.s ! VPerf vagr) ; -- rqadt => b2 ma (verb.s ! VPerf vagr) ; -- ma rqadtx => b2 kien (verb.s ! VPerf vagr) ; -- kont rqadt => b2 (ma ++ kienx) (verb.s ! VPerf vagr) ; -- ma kontx rqadt => b2 ("se" ++ nkun) (verb.s ! VPerf vagr) ; -- se nkun rqadt => b2 (mhux ! vagr ++ "se" ++ nkun) (verb.s ! VPerf vagr) -- m'iniex se nkun rqadt } ; -- Join verb phrase components into a string joinVP : VerbPhrase -> Tense -> Anteriority -> Polarity -> Agr -> Str = \vp,tense,ant,pol,agr -> let stems = (pickVerbForm vp.v tense ant pol agr).main ; aux = (pickVerbForm vp.v tense ant pol agr).aux ; x : Str = "x" ; vagr : VAgr = toVAgr agr ; dir_a : Agr = fromJust Agr vp.dir ; -- These are lazy ind_a : Agr = fromJust Agr vp.ind ; dir = dirObjSuffix dir_a ; ind = indObjSuffix ind_a ; ind_pos : Str = case of { => ind.s3 ; -- hom-lok _ => ind.s1 -- hie-lek } ; ind_neg : Str = case of { => ind.s4 ; -- hom-lokx _ => ind.s2 -- hie-lekx } ; in case takesAux tense ant of { -- aux is already negated for us True => aux ++ case of { -- konna ftaħna / ma konniex ftaħna => stems.s1 ; -- konna ftaħnie-ha / ma konniex ftaħni-ha => stems.s2 ++ BIND ++ dir.s1 ; -- konna ftaħnie-lha / ma konniex ftaħni-lha => stems.s2 ++ BIND ++ ind.s1 ; -- konna ftaħni-hie-lha / ma konniex ftaħni-hi-lha => stems.s3 ++ BIND ++ dir.s2 ++ BIND ++ ind.s1 } ; -- No aux part to handle False => aux ++ case isPerf tense ant of { True => case of { -- ftaħna / ftaħnie-x => stems.s1 ; => stems.s2 ++ BIND ++ x ; -- ftaħnie-ha / ftaħni-hie-x => stems.s2 ++ BIND ++ dir.s1 ; => stems.s3 ++ BIND ++ dir.s2 ++ BIND ++ x ; -- ftaħnie-lha / ftaħni-lhie-x => case of { => stems.s2 ++ BIND ++ ind.s3 ; -- fetħ-ilha => stems.s2 ++ BIND ++ ind.s1 ; -- ftaħnie-lha _ => stems.s1 ++ BIND ++ ind.s1 -- fetaħ-li } ; => case of { => stems.s2 ++ BIND ++ ind.s4 ++ BIND ++ x ; -- fetħ-ilhiex => stems.s3 ++ BIND ++ ind.s2 ++ BIND ++ x ; -- ftaħni-lhiex _ => stems.s1 ++ BIND ++ ind.s2 ++ BIND ++ x -- fetaħ-lix } ; -- ftaħni-hie-lha / ftaħni-hi-lhie-x => stems.s2 ++ BIND ++ dir.s2 ++ BIND ++ ind_pos ; => stems.s3 ++ BIND ++ dir.s3 ++ BIND ++ ind_neg ++ BIND ++ x } ; False => case of { -- jiftaħ / jiftaħ-x => stems.s1 ; => stems.s1 ++ BIND ++ x ; -- jiftaħ-ha / jiftaħ-hie-x => stems.s1 ++ BIND ++ dir.s1 ; => stems.s1 ++ BIND ++ dir.s2 ++ BIND ++ x ; -- jiftħ-ilha / jiftħ-ilhie-x => case of { => stems.s2 ++ BIND ++ ind.s3 ; -- jiftħ-ilha => stems.s2 ++ BIND ++ ind.s1 ; -- jiftħu-lha _ => stems.s1 ++ BIND ++ ind.s1 -- jiftaħ-li } ; => case of { => stems.s2 ++ BIND ++ ind.s4 ++ BIND ++ x ; -- jiftħ-ilhiex => stems.s2 ++ BIND ++ ind.s2 ++ BIND ++ x ; -- jiftħu-lhiex _ => stems.s1 ++ BIND ++ ind.s2 ++ BIND ++ x -- jiftaħ-lix } ; -- jiftaħ-hie-lha / jiftaħ-hi-lhie-x => stems.s1 ++ BIND ++ dir.s2 ++ BIND ++ ind_pos ; => stems.s1 ++ BIND ++ dir.s3 ++ BIND ++ ind_neg ++ BIND ++ x } } } ; -- Does a tense + ant take an auxiliary verb? -- This affects where (if) the negation is applied -- This is a workaround to avoid having a bool param in VerbParts -- Must match with the logic in pickVerbForm takesAux : Tense -> Anteriority -> Bool = \tense,ant -> case of { => False ; => False ; => True ; => True ; => False ; => True ; => True ; => True } ; -- Does a tense + ant give a perfective verb? -- Must match with the logic in pickVerbForm isPerf : Tense -> Anteriority -> Bool = \tense,ant -> case of { => False ; => True ; => False ; => False ; => True ; => True ; => True ; => False } ; VerbParts : Type = { aux : Str ; -- when present, negation is applied here main : VerbStems ; -- enclitics always applied here } ; mkVerbParts = overload { mkVerbParts : VerbStems -> VerbParts = \vs -> { aux = [] ; main = vs } ; mkVerbParts : Str -> VerbParts = \m -> { aux = [] ; main = mkVerbStems m } ; mkVerbParts : Str -> VerbStems -> VerbParts = \a,vs -> { aux = a ; main = vs } ; mkVerbParts : Str -> Str -> VerbParts = \a,m -> { aux = a ; main = mkVerbStems m } ; } ; VerbPhrase : Type = { -- v : Verb ; v : { s : VForm => VerbStems ; presPart : Maybe Participle ; pastPart : Maybe Participle ; } ; s2 : Agr => Str ; -- complement dir : Maybe Agr ; -- direct object clitic ind : Maybe Agr ; -- indirect object clitic } ; SlashVerbPhrase : Type = VerbPhrase ** {c2 : Compl} ; oper insertObj : (Agr => Str) -> VerbPhrase -> VerbPhrase = \obj,vp -> { v = vp.v ; s2 = \\agr => vp.s2 ! agr ++ obj ! agr ; dir = vp.dir ; ind = vp.ind ; } ; insertObjPre : (Agr => Str) -> VerbPhrase -> VerbPhrase = \obj,vp -> { v = vp.v ; s2 = \\agr => obj ! agr ++ vp.s2 ! agr ; dir = vp.dir ; ind = vp.ind ; } ; insertObjc : (Agr => Str) -> SlashVerbPhrase -> SlashVerbPhrase = \obj,vp -> insertObj obj vp ** {c2 = vp.c2} ; insertDirObj : Agr -> VerbPhrase -> VerbPhrase = \dir,vp -> { v = vp.v ; s2 = vp.s2 ; dir = Just Agr dir ; ind = vp.ind ; }; insertIndObj : Agr -> VerbPhrase -> VerbPhrase = \ind,vp -> { v = vp.v ; s2 = vp.s2 ; dir = vp.dir ; ind = Just Agr ind ; }; insertAdV : Str -> VerbPhrase -> VerbPhrase = \adv,vp -> { v = vp.v ; s2 = \\agr => vp.s2 ! agr ++ adv ; dir = vp.dir ; ind = vp.ind ; } ; predVc : (Verb ** {c2 : Compl}) -> SlashVerbPhrase = \verb -> predV verb ** {c2 = verb.c2} ; copula_kien : {s : VForm => Polarity => Str} = { s = \\vform,pol => case of { => "kont" ; => "kont" ; => "kien" ; => "kienet" ; => "konna" ; => "kontu" ; => "kienu" ; => "nkun" ; => "tkun" ; => "jkun" ; => "tkun" ; => "nkunu" ; => "tkunu" ; => "jkunu" ; => "kun" ; => "kunu" ; => "kontx" ; => "kontx" ; => "kienx" ; => "kinitx" ; => "konniex" ; => "kontux" ; => "kienux" ; => "nkunx" ; => "tkunx" ; => "jkunx" ; => "tkunx" ; => "nkunux" ; => "tkunux" ; => "jkunux" ; => "kunx" ; => "kunux" } } ; -- Adapted from [AZ] CopulaVP : VerbPhrase = { -- s = \\vpf,ant,pol => -- --- We are ignoring the anteriority -- case of { -- --- Here we are bypassing VerbParts by putting negatives in the stem -- -- => mkVerbParts (copula_kien.s ! VImpf vagr ! Pos) [] ; -- jkun -- -- => mkVerbParts (copula_kien.s ! VImpf vagr ! Neg) [] ; -- ma jkunx -- => mkVerbParts (huwa ! vagr) [] ; -- huwa -- => mkVerbParts (mhux ! vagr) [] ; -- m'huwiex -- => mkVerbParts (copula_kien.s ! VPerf vagr ! Pos) [] ; -- kien -- => mkVerbParts (copula_kien.s ! VPerf vagr ! Neg) [] ; -- ma kienx -- => mkVerbParts ("se" ++ copula_kien.s ! VImpf vagr ! Pos) [] ; -- se jkun -- => mkVerbParts (mhux ! vagr ++ "se" ++ copula_kien.s ! VImpf vagr ! Pos) [] ; -- mhux se jkun -- => mkVerbParts ("kieku" ++ copula_kien.s ! VPerf vagr ! Pos) [] ; -- kieku kien -- => mkVerbParts ("kieku" ++ "ma" ++ copula_kien.s ! VPerf vagr ! Neg) [] ; -- kieku ma kienx -- => mkVerbParts (copula_kien.s ! VImp num ! Pos) [] ; -- kun -- => mkVerbParts (copula_kien.s ! VImp num ! Neg) [] -- kunx -- } ; v = { s = table { VPerf (AgP1 Sg) => mkVerbStems "kont" ; VPerf (AgP2 Sg) => mkVerbStems "kont" ; VPerf (AgP3Sg Masc) => mkVerbStems "kien" ; VPerf (AgP3Sg Fem) => mkVerbStems "kienet" "kinit" ; VPerf (AgP1 Pl) => mkVerbStems "konna" "konnie" ; VPerf (AgP2 Pl) => mkVerbStems "kontu" ; VPerf (AgP3Pl) => mkVerbStems "kienu" ; VImpf (AgP1 Sg) => mkVerbStems [] "m'inie" ; VImpf (AgP2 Sg) => mkVerbStems [] "m'inti"; VImpf (AgP3Sg Masc) => mkVerbStems "huwa" "m'hu" ; VImpf (AgP3Sg Fem) => mkVerbStems "hija" "m'hi" ; VImpf (AgP1 Pl) => mkVerbStems [] "m'aħnie" ; VImpf (AgP2 Pl) => mkVerbStems [] "m'intom" ; VImpf (AgP3Pl) => mkVerbStems "huma" "m'humie" ; VImp (Sg) => mkVerbStems "kun" ; VImp (Pl) => mkVerbStems "kunu" } ; i = mkVerbInfo Irregular FormI ; presPart = noParticiple ; pastPart = noParticiple ; } ; s2 = \\agr => [] ; dir = NullAgr ; ind = NullAgr ; } ; predV : Verb -> VerbPhrase = \verb -> { v = verb ; s2 = \\agr => [] ; dir = NullAgr ; ind = NullAgr ; } ; -- There is no infinitive in Maltese; use imperfective infVP : VerbPhrase -> Anteriority -> Polarity -> Agr -> Str = \vp,ant,pol,agr -> joinVP vp Pres ant pol agr ++ vp.s2 ! agr ; Aux = { s : Tense => Polarity => Str ; } ; auxHemm : Aux = { s = \\t,p => case of { => "hemm" ; => "m'hemmx" ; => "kien hemm" ; => "ma kienx hemm" ; => "ħa jkun hemm" ; => "mhux ħa jkun hemm" ; => "jekk hemm" ; => "jekk hemmx" } } ; reflPron : VAgr => Str = table { -- AgP1 Sg => "lili nnifsi" ; -- AgP2 Sg => "lilek innifsek" ; -- AgP3Sg Masc => "lilu nnifsu" ; -- AgP3Sg Fem => "lila nnifisha" ; -- AgP1 Pl => "lilna nfusna" ; -- AgP2 Pl => "lilkom infuskom" ; -- AgP3Pl => "lilhom infushom" AgP1 Sg => "nnifsi" ; AgP2 Sg => "innifsek" ; AgP3Sg Masc => "nnifsu" ; AgP3Sg Fem => "nnifisha" ; AgP1 Pl => "nfusna" ; AgP2 Pl => "infuskom" ; AgP3Pl => "infushom" } ; huwa : VAgr => Str = table { AgP1 Sg => "jiena" ; AgP2 Sg => "inti" ; AgP3Sg Masc => "huwa" ; AgP3Sg Fem => "hija" ; AgP1 Pl => "aħna" ; AgP2 Pl => "intom" ; AgP3Pl => "huma" } ; mhux : VAgr => Str = table { AgP1 Sg => "m'iniex" ; AgP2 Sg => "m'intix" ; AgP3Sg Masc => "m'hux" ; AgP3Sg Fem => "m'hix" ; AgP1 Pl => "m'aħniex" ; AgP2 Pl => "m'intomx" ; AgP3Pl => "m'humiex" } ; conjLi : Str = "li" ; conjThat = conjLi ; {- Adjecive ------------------------------------------------------------ -} oper Adjective : Type = { s : AForm => Str ; hasComp : Bool ; } ; param AForm = APosit GenNum -- Positive, e.g. SABIĦ | ACompar -- Comparative, e.g. ISBAĦ | ASuperl -- Superlative, e.g. L-ISBAĦ ; oper -- adjective: Takes all forms (except superlative) -- Params: -- Masculine, eg SABIĦ -- Feminine, eg SABIĦA -- Plural, eg SBIEĦ -- Comparative, eg ISBAĦ mkAdjective : (_,_,_,_ : Str) -> Adjective = \masc,fem,plural,compar -> { s = table { APosit gn => case gn of { GSg Masc => masc ; GSg Fem => fem ; GPl => plural } ; ACompar => compar ; ASuperl => artDef ++ compar } ; hasComp = notB (isNil compar) ; } ; {- Other ---------------------------------------------------------------- -} oper {- ~~~ Some character classes ~~~ -} Letter : pattern Str = #( "a" | "b" | "ċ" | "d" | "e" | "f" | "ġ" | "g" | "għ" | "h" | "ħ" | "i" | "ie" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "ż" | "z" ); Consonant : pattern Str = #( "b" | "ċ" | "d" | "f" | "ġ" | "g" | "għ" | "h" | "ħ" | "j" | "k" | "l" | "m" | "n" | "p" | "q" | "r" | "s" | "t" | "v" | "w" | "x" | "ż" | "z" ); CoronalCons : pattern Str = #( "ċ" | "d" | "n" | "r" | "s" | "t" | "x" | "ż" | "z" ); -- "konsonanti xemxin" LiquidCons : pattern Str = #( "l" | "m" | "n" | "r" | "għ" ); SonorantCons : pattern Str = #( "l" | "m" | "n" | "r" ); -- See {SA pg13}. Currently unused, but see DoublingConsN below DoublingConsT : pattern Str = #( "ċ" | "d" | "ġ" | "s" | "x" | "ż" | "z" ); -- require doubling when prefixed with 't', eg DDUM, ĠĠORR, SSIB, TTIR, ŻŻID {GM pg68,2b} {OM pg90} DoublingConsN : pattern Str = #( "l" | "m" | "r" ); -- require doubling when prefixed with 'n', eg LLAĦĦAQ, MMUR, RRID {OM pg90} StrongCons : pattern Str = #( "b" | "ċ" | "d" | "f" | "ġ" | "g" | "għ" | "h" | "ħ" | "k" | "l" | "m" | "n" | "p" | "q" | "r" | "s" | "t" | "v" | "x" | "ż" | "z" ); WeakCons : pattern Str = #( "j" | "w" ); Vowel : pattern Str = #( "a" | "e" | "i" | "o" | "u" ); VowelIE : pattern Str = #( "a" | "e" | "i" | "ie" | "o" | "u" ); Digraph : pattern Str = #( "ie" ); SemiVowel : pattern Str = #( "għ" | "j" ); Vwl = Vowel ; Cns = Consonant ; LCns = LiquidCons ; EorI : Str = "e" | "i" ; IorE : Str = "i" | "e" ; {- ~~~ Roots & Vowel sequences ~~~ -} Vowels : Type = {V1, V2 : Str} ; Root : Type = {C1, C2, C3, C4 : Str} ; -- Make a root object. Accepts following overloads: -- mkoot (empty root) -- mkRoot "k-t-b" / mkRoot "k-t-b-l" -- mkRoot "k" "t" "b" -- mkRoot "k" "t" "b" "l" mkRoot : Root = overload { mkRoot : Root = { C1=[] ; C2=[] ; C3=[] ; C4=[] } ; mkRoot : Str -> Root = \s -> case toLower s of { c1 + "-" + c2 + "-" + c3 + "-" + c4 => { C1=c1 ; C2=c2 ; C3=c3 ; C4=c4 } ; -- "k-t-b-l" c1 + "-" + c2 + "-" + c3 => { C1=c1 ; C2=c2 ; C3=c3 ; C4=[] } ; -- "k-t-b" _ => Predef.error("Cannot make root from:"++s) } ; mkRoot : Str -> Str -> Str -> Root = \c1,c2,c3 -> { C1=toLower c1 ; C2=toLower c2 ; C3=toLower c3 ; C4=[] } ; mkRoot : Str -> Str -> Str -> Str -> Root = \c1,c2,c3,c4 -> { C1=toLower c1 ; C2=toLower c2 ; C3=toLower c3 ; C4=toLower c4 } ; } ; mkVowels : Vowels = overload { mkVowels : Vowels = { V1=[] ; V2=[] } ; mkVowels : Str -> Vowels = \v1 -> { V1=toLower v1 ; V2=[] } ; mkVowels : Str -> Str -> Vowels = \v1,v2 -> { V1=toLower v1 ; V2=case v2 of {"" => [] ; _ => toLower v2}} ; } ; -- Extract first two vowels from a token (designed for semitic verb forms) --- potentially slow extractVowels : Str -> Vowels = \s -> case s of { v1@"ie" + _ + v2@#Vowel + _ => mkVowels v1 v2 ; -- IEQAF v1@#Vowel + _ + v2@#Vowel + _ => mkVowels v1 v2 ; -- IKTEB _ + v1@"ie" + _ + v2@#Vowel + _ => mkVowels v1 v2 ; -- RIEQED _ + v1@"ie" + _ => mkVowels v1 ; -- ŻIED _ + v1@#Vowel + _ + v2@#Vowel + _ => mkVowels v1 v2 ; -- ĦARBAT _ + v1@#Vowel + _ => mkVowels v1 ; -- ĦOBB _ => mkVowels } ; -- Create a VerbInfo record, optionally omitting various fields mkVerbInfo : VerbInfo = overload { mkVerbInfo : VClass -> VDerivedForm -> VerbInfo = \c,f -> { class=c ; form=f ; root=mkRoot ; vseq=mkVowels ; imp=[] } ; mkVerbInfo : VClass -> VDerivedForm -> Str -> VerbInfo = \c,f,i -> { class=c ; form=f ; root=mkRoot ; vseq=mkVowels ; imp=i } ; mkVerbInfo : VClass -> VDerivedForm -> Root -> Vowels -> VerbInfo = \c,f,r,p -> { class=c ; form=f ; root=r ; vseq=p ; imp=[] } ; mkVerbInfo : VClass -> VDerivedForm -> Root -> Vowels -> Str -> VerbInfo = \c,f,r,p,i -> { class=c ; form=f ; root=r ; vseq=p ; imp=i } ; -- mkVerbInfo : VClass -> VDerivedForm -> Root -> Vowels -> Vowels -> Str -> VerbInfo = \c,f,r,p,p2,i -> -- { class=c ; form=f ; root=r ; vseq=p ; vseq2=p2 ; imp=i } ; } ; -- Change certain fields of a VerbInfo record updateVerbInfo : VerbInfo = overload { -- Root updateVerbInfo : VerbInfo -> Root -> VerbInfo = \i,r -> { class=i.class ; form=i.form ; root=r ; vseq=i.vseq ; imp=i.imp } ; -- DerivedForm updateVerbInfo : VerbInfo -> VDerivedForm -> VerbInfo = \i,f -> { class=i.class ; form=f ; root=i.root ; vseq=i.vseq ; imp=i.imp } ; -- DerivedForm, Imperative updateVerbInfo : VerbInfo -> VDerivedForm -> Str -> VerbInfo = \i,f,imp -> { class=i.class ; form=f ; root=i.root ; vseq=i.vseq ; imp=imp } ; } ; -- Return the class for a given root classifyRoot : Root -> VClass = \r -> case of { <#WeakCons, #StrongCons, #StrongCons, ""> => Weak Assimilative ; <#StrongCons, #WeakCons, #StrongCons, ""> => Weak Hollow ; <#StrongCons, #StrongCons, #WeakCons, ""> => Weak Lacking ; <#StrongCons, #WeakCons, #WeakCons, ""> => Weak Lacking ; <#Consonant, #Consonant, "għ", ""> => Weak Defective ; <#Consonant, c2@#Consonant, c3@#Consonant, ""> => if_then_else VClass (pbool2bool (eqStr c2 c3)) (Strong Geminated) (case c2 of { #LiquidCons => Strong LiquidMedial ; _ => Strong Regular }) ; <#Consonant, #Consonant, #Consonant, #WeakCons> => Quad QWeak ; <#Consonant, #Consonant, #Consonant, #Consonant> => Quad QStrong ; -- Irregular <"'",_,_,_> => Irregular ; <_,"'",_,_> => Irregular ; <_,_,"'",_> => Irregular ; <_,_,_,"'"> => Irregular ; <_,_,_,""> => Predef.error("Cannot classify root:"++r.C1+"-"+r.C2+"-"+r.C3) ; <_,_,_,_> => Predef.error("Cannot classify root:"++r.C1+"-"+r.C2+"-"+r.C3+"-"+r.C4) } ; {- ~~~ Useful helper functions ~~~ -} -- New names for the drop/take operations takePfx = Predef.take ; dropPfx = Predef.drop ; takeSfx = Predef.dp ; dropSfx = Predef.tk ; -- Get the character at the specific index (0-based). -- Negative indices behave as 0 (first character). Out of range indexes return the empty string. charAt : Int -> Str -> Str ; charAt i s = takePfx 1 (dropPfx i s) ; -- Delete character at the specific index (0-based). -- Out of range indices are just ignored. delCharAt : Int -> Str -> Str ; delCharAt i s = (takePfx i s) + (dropPfx (plus i 1) s) ; -- -- Replace first substring -- replace : Str -> Str -> Str -> Str ; -- replace needle haystack replacement = -- case haystack of { -- x + needle + y => x + replacement + y ; -- _ => haystack -- } ; -- Prefix with a 'n'/'t' or double initial consonant, as necessary. See {OM pg 90} pfx_N : Str -> Str = \s -> case s of { "" => [] ; m@#DoublingConsN + _ => m + s ; _ => "n" + s } ; pfx_T : Str -> Str = \s -> case s of { "" => [] ; d@#DoublingConsT + _ => d + s ; _ => "t" + s } ; pfx_J : Str -> Str = \s -> pfx "j" s ; -- Generically prefix a string (avoiding empty strings) pfx : Str -> Str -> Str = \p,s -> case of { <_, ""> => [] ; <"", str> => str ; => px + str } ; -- Add suffix, avoiding triple letters {GO pg96-7} --- add more cases? --- potentially slow sfx : Str -> Str -> Str = \a,b -> case of { <"",_> => [] ; => ke+"n"+b ; => ha+"k"+b ; => ho+"l"+b ; => si+"t"+b ; => be+"x"+b ; _ => a + b } ; -- Replace any IE in the word with an I or E --- potentially slow ie2i : Str -> Str = ie2_ "i" ; ie2e : Str -> Str = ie2_ "e" ; ie2_ : Str -> Str -> Str = \iore,serviet -> case serviet of { x + "ie" => x + iore ; x + "ie" + y => x + iore + y ; x => x } ; -- Is a word mono-syllabic? --- potentially slow -- isMonoSyl : Str -> Bool = \s -> -- case s of { -- #Consonant + ("ie" | #Vowel) => True ; -- ra -- #Consonant + #Consonant + ("ie" | #Vowel) => True ; -- bla -- ("ie" | #Vowel) + #Consonant => True ; -- af -- ("ie" | #Vowel) + #Consonant + #Consonant => True ; -- elf -- #Consonant + ("ie" | #Vowel) + #Consonant => True ; -- miet -- #Consonant + ("ie" | #Vowel) + #Consonant + #Consonant => True ; -- mort -- #Consonant + #Consonant + ("ie" | #Vowel) + #Consonant => True ; -- ħliet -- #Consonant + #Consonant + ("ie" | #Vowel) + #Consonant + #Consonant => True ; -- ħriġt -- _ => False -- } ; wiehed : Gender => Str = table { Masc => "wieħed" ; Fem => "waħda" } ; artIndef : Str = [] ; --- is this a source of leaks? artDef : Str = makePreFull "il-" -- il-ktieb "i" -- it-triq "l-" -- l-ajruplan ; -- Make a pre string which only varies for vowels makePreVowel : Str -> Str -> Str = \cons,vowel -> let vowel' : Str = case vowel of { _ + "'" => vowel ++ BIND ; _ => vowel } ; in pre { -- Consonant cons ; -- Vowel vowel' / strs { "a" ; "e" ; "i" ; "o" ; "u" ; "h" ; "għ" } } ; -- Make a pre string which varies coronal consonants and vowels makePreFull : Str -> Str -> Str -> Str = \cons,corcons,vowel -> let mal = cons ++ BIND ; m' = vowel ++ BIND ; ma = corcons ; in pre { -- Regular consonant mal ; -- Vowel m' / strs { "a" ; "e" ; "i" ; "o" ; "u" ; "h" ; "għ" } ; -- Coronal consonants ma+"ċ-" ++ BIND / strs { "ċ" } ; ma+"d-" ++ BIND / strs { "d" } ; ma+"n-" ++ BIND / strs { "n" } ; ma+"r-" ++ BIND / strs { "r" } ; ma+"s-" ++ BIND / strs { "s" } ; ma+"t-" ++ BIND / strs { "t" } ; ma+"x-" ++ BIND / strs { "x" } ; ma+"ż-" ++ BIND / strs { "ż" } ; ma+"z-" ++ BIND / strs { "z" } } ; }