-- 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; VPForm2VAgr : VPForm -> VAgr = \vpform -> case vpform of { VPIndicat _ vagr => vagr ; VPImperat n => AgP2 n }; 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 } ; -- Clause mkClause : Str -> Agr -> VerbPhrase -> Clause = \subj,agr,vp -> { s = \\t,a,p,o => let -- verb = vp.s ! t ! a ! p ! o ! agr ; -- vform = case of { -- _ => VPres -- } ; vpform : VPForm = VPIndicat t (toVAgr agr) ; verb : Str = joinVP vp vpform a p ; compl : Str = vp.s2 ! agr ; in case o of { -- ODir => subj ++ verb.aux ++ verb.adv ++ vp.ad ++ verb.fin ++ verb.inf ++ vp.p ++ compl ; -- OQuest => verb.aux ++ subj ++ verb.adv ++ vp.ad ++ verb.fin ++ verb.inf ++ vp.p ++ compl -- ABSOLUTELY NOT CORRECT: in progress ODir => subj ++ verb ++ compl ; OQuest => subj ++ verb ++ compl } } ; 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 --- Overlap between Num Sg and Num1, but leaving as is for now NumForm = NumX Number -- Sg | Pl | Num0 -- 0 (l-edba SIEGĦA) | Num1 -- 1, 101... (SIEGĦA, 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 -- [AZ] Determiner : Type = { s : Gender => Str ; n : NumForm ; clitic : Str ; hasNum : Bool ; -- has a numeral isPron : Bool ; -- is a pronoun isDefn : Bool ; -- is definite } ; -- Determiner = { -- s : NPCase => Gender => NumCase => Str ; -- s2 : NPCase => Gender => Str ; -- tieghi (possessive pronoun) -- -- size : Num_Size ; -- One (agreement feature for noun) -- isNum : Bool ; -- True (a numeral is present) -- isDemo : Bool ; -- True (is a demostrative) -- isDefn : Bool ;-- True (is definite) -- } ; -- [AZ] Quantifier : Type = { s : GenNum => Str ; clitic : Str ; isPron : Bool ; isDemo : Bool ; -- Demonstrative (this/that/those/these) isDefn : Bool ; -- is definite } ; -- Quantifier = { -- s : NPCase => Gender => NumForm => Str ; -- s2 : NPCase => Gender => NumForm => Str ; -- isDemo : Bool ; -- Demonstrative (this/that/those/these) -- isDefn : Bool ; -- } ; {- 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} ; -- Compl : Type = { -- s : Str ; -- -- c : NPForm ; -- -- isPre : Bool -- } ; noCompl : Compl = { s = \\_ => [] ; enclitic = \\_ => [] ; takesDet = False ; joinsVerb = False ; isPresent = False ; } ; 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) } ; {- 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 -- Generic variants (used for verb stems) Variants3 : Type = {s1, s2, s3 : Str} ; mkVariants3 : Variants3 = overload { mkVariants3 : (s1 : Str) -> Variants3 = \a -> { s1 = a ; s2 = a ; s3 = a } ; mkVariants3 : (s1, s2, s3 : Str) -> Variants3 = \a,b,c -> { s1 = a ; s2 = b ; s3 = c } ; } ; mkMaybeVariants3 : Str -> Maybe Variants3 = \s -> Just Variants3 (mkVariants3 s) ; NullVariants3 : Maybe Variants3 = Nothing Variants3 { s1 = [] ; s2 = [] ; s3 = [] } ; 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 -> Variants3 = \s -> let ftahna : Str = s ; ftahnie : Str = case s of { ftahn + "a" => ftahn + "ie" ; fet + h@#Cns + "et" => fet + h + "it" ; fet + "aħ" => fet + "ħ" ; _ => s } ; ftahni : Str = case s of { ftahn + "a" => ftahn + "i" ; _ => ftahnie } ; in { s1 = ftahna ; s2 = ftahnie ; s3 = ftahni ; } ; stemVariantsImpf : Str -> Variants3 = \s -> let jiftah : Str = s ; jifth : Str = case s of { jift + "aħ" => jift + "ħ" ; _ => s } ; in { s1 = jiftah ; s2 = jifth ; s3 = jifth ; } ; -- Convert old verb form table into one with stem variants stemVariantsTbl : (VForm => Str) -> (VForm => Variants3) = \tbl -> \\vf => case vf of { VPerf _ => stemVariantsPerf (tbl ! vf) ; VImpf _ => stemVariantsImpf (tbl ! vf) ; _ => mkVariants3 (tbl ! vf) } ; Verb : Type = { s : VForm => Variants3 ; --- need to store different "stems" already at verb level (ġera/ġerie/ġeri) i : VerbInfo ; } ; VerbInfo : Type = { class : VClass ; form : VDerivedForm ; root : Root ; -- radicals patt : Pattern ; -- vowels extracted from mamma patt2 : Pattern ; -- vowel changes; default to patt (experimental) -- in particular, patt2 is used to indicate whether an IE sould be shortened -- to an I or an E (same for entire verb) imp : Str ; -- Imperative Sg. Gives so much information jaħasra! } ; param -- Possible verb forms (tense + person) 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 | VActivePart GenNum -- Present/active particible, e.g. RIEQED | VPassivePart GenNum -- Passive/past particible, e.g. MAĦBUB -- | VVerbalNoun -- Verbal Noun ; 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 -- Join verp phrase components into a string joinVP : VerbPhrase -> VPForm -> Anteriority -> Polarity -> Str = \vp,form,ant,pol -> let stems = (vp.s ! form ! ant ! pol).main ; aux = (vp.s ! form ! ant ! pol).aux ; x : Str = "x" ; agr : VAgr = VPForm2VAgr form ; 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 form 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 form 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 predV takesAux : VPForm -> Anteriority -> Bool = \vpf,ant -> case of { => False ; => False ; => True ; => True ; => False ; => True ; => True ; => True ; => False } ; -- Does a tense + ant give a perfective verb? -- Must match with the logic in predV isPerf : VPForm -> Anteriority -> Bool = \vpf,ant -> case of { => False ; => True ; => False ; => False ; => True ; => True ; => True ; => False ; => False } ; VerbParts : Type = { aux : Str ; -- when present, negation is applied here main : Variants3 ; -- enclitics always applied here } ; mkVerbParts = overload { mkVerbParts : Variants3 -> VerbParts = \vs -> { aux = [] ; main = vs } ; mkVerbParts : Str -> VerbParts = \m -> { aux = [] ; main = mkVariants3 m } ; mkVerbParts : Str -> Variants3 -> VerbParts = \a,vs -> { aux = a ; main = vs } ; mkVerbParts : Str -> Str -> VerbParts = \a,m -> { aux = a ; main = mkVariants3 m } ; } ; VerbPhrase : Type = { s : VPForm => Anteriority => Polarity => VerbParts ; s2 : Agr => Str ; -- complement dir : Maybe Agr ; -- direct object clitic ind : Maybe Agr ; -- indirect object clitic } ; SlashVerbPhrase : Type = VerbPhrase ** {c2 : Compl} ; param -- [AZ] VPForm = VPIndicat Tense VAgr | VPImperat Number ; oper insertObj : (Agr => Str) -> VerbPhrase -> VerbPhrase = \obj,vp -> { s = vp.s ; s2 = \\agr => vp.s2 ! agr ++ obj ! agr ; dir = vp.dir ; ind = vp.ind ; } ; insertObjPre : (Agr => Str) -> VerbPhrase -> VerbPhrase = \obj,vp -> { s = vp.s ; 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 -> { s = vp.s ; s2 = vp.s2 ; dir = Just Agr dir ; ind = vp.ind ; }; insertIndObj : Agr -> VerbPhrase -> VerbPhrase = \ind,vp -> { s = vp.s ; s2 = vp.s2 ; dir = vp.dir ; ind = Just Agr ind ; }; insertAdV : Str -> VerbPhrase -> VerbPhrase = \adv,vp -> { s = vp.s ; 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 ! VPerf vagr ! Pos) [] ; -- kien => mkVerbParts (copula_kien.s ! VImpf vagr ! Pos) [] ; -- jkun => mkVerbParts ("se" ++ copula_kien.s ! VImpf vagr ! Pos) [] ; -- se jkun => mkVerbParts ("kieku" ++ copula_kien.s ! VPerf vagr ! Pos) [] ; -- kieku kien => mkVerbParts (copula_kien.s ! VImp num ! Pos) [] ; -- kun => mkVerbParts (copula_kien.s ! VPerf vagr ! Neg) [] ; -- ma kienx => mkVerbParts (copula_kien.s ! VImpf vagr ! Neg) [] ; -- ma jkunx => mkVerbParts (mhux ! vagr ++ "se" ++ copula_kien.s ! VImpf vagr ! Pos) [] ; -- mhux se jkun => mkVerbParts ("kieku" ++ "ma" ++ copula_kien.s ! VPerf vagr ! Neg) [] ; -- kieku ma kienx => mkVerbParts (copula_kien.s ! VImp num ! Neg) [] -- kunx } ; s2 = \\agr => [] ; dir = NullAgr ; ind = NullAgr ; } ; -- [AZ] predV : Verb -> VerbPhrase = \verb -> { s = \\vpf,ant,pol => let ma = makePreVowel "ma" "m'" ; b1 : Variants3 -> VerbParts = \vs -> mkVerbParts vs ; b2 : Str -> Variants3 -> VerbParts = \s,vs -> mkVerbParts s vs ; in case vpf of { VPIndicat tense vagr => let 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 } ; VPImperat num => b1 (verb.s ! VImp num) -- torqodx }; s2 = \\agr => [] ; dir = NullAgr ; ind = NullAgr ; } ; -- There is no infinitive in Maltese; use perfective infVP : VerbPhrase -> Anteriority -> Polarity -> Agr -> Str = \vp,ant,pol,agr -> let vpform : VPForm = VPIndicat Past (toVAgr agr) ; in joinVP vp vpform ant pol ++ 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" } ; 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 & Patterns ~~~ -} Pattern : 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 } ; } ; mkPattern : Pattern = overload { mkPattern : Pattern = { V1=[] ; V2=[] } ; mkPattern : Str -> Pattern = \v1 -> { V1=toLower v1 ; V2=[] } ; mkPattern : Str -> Str -> Pattern = \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 extractPattern : Str -> Pattern = \s -> case s of { v1@"ie" + _ + v2@#Vowel + _ => mkPattern v1 v2 ; -- IEQAF v1@#Vowel + _ + v2@#Vowel + _ => mkPattern v1 v2 ; -- IKTEB _ + v1@"ie" + _ + v2@#Vowel + _ => mkPattern v1 v2 ; -- RIEQED _ + v1@"ie" + _ => mkPattern v1 ; -- ŻIED _ + v1@#Vowel + _ + v2@#Vowel + _ => mkPattern v1 v2 ; -- ĦARBAT _ + v1@#Vowel + _ => mkPattern v1 ; -- ĦOBB _ => mkPattern } ; -- Create a VerbInfo record, optionally omitting various fields mkVerbInfo : VerbInfo = overload { mkVerbInfo : VClass -> VDerivedForm -> VerbInfo = \c,f -> { class=c ; form=f ; root=mkRoot ; patt=mkPattern ; patt2=mkPattern ; imp=[] } ; mkVerbInfo : VClass -> VDerivedForm -> Str -> VerbInfo = \c,f,i -> { class=c ; form=f ; root=mkRoot ; patt=mkPattern ; patt2=mkPattern ; imp=i } ; mkVerbInfo : VClass -> VDerivedForm -> Root -> Pattern -> VerbInfo = \c,f,r,p -> { class=c ; form=f ; root=r ; patt=p ; patt2=p ; imp=[] } ; mkVerbInfo : VClass -> VDerivedForm -> Root -> Pattern -> Str -> VerbInfo = \c,f,r,p,i -> { class=c ; form=f ; root=r ; patt=p ; patt2=p ; imp=i } ; mkVerbInfo : VClass -> VDerivedForm -> Root -> Pattern -> Pattern -> Str -> VerbInfo = \c,f,r,p,p2,i -> { class=c ; form=f ; root=r ; patt=p ; patt2=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 ; patt=i.patt ; patt2=i.patt2 ; imp=i.imp } ; -- DerivedForm updateVerbInfo : VerbInfo -> VDerivedForm -> VerbInfo = \i,f -> { class=i.class ; form=f ; root=i.root ; patt=i.patt ; patt2=i.patt2 ; imp=i.imp } ; -- DerivedForm, Imperative updateVerbInfo : VerbInfo -> VDerivedForm -> Str -> VerbInfo = \i,f,imp -> { class=i.class ; form=f ; root=i.root ; patt=i.patt ; patt2=i.patt2 ; imp=imp } ; } ; {- ~~~ 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 } ; artIndef : Str = "" ; 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" } } ; }