forked from GitHub/gf-core
Of course some bugs remain and more testing is needed, but all functions are complete and Maltese now builds as part of the normal GF install.
1216 lines
40 KiB
Plaintext
1216 lines
40 KiB
Plaintext
-- 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 <agr.p,agr.n> of {
|
|
<P1,num> => AgP1 num;
|
|
<P2,num> => AgP2 num;
|
|
<P3,Sg> => AgP3Sg agr.g;
|
|
<P3,Pl> => 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 <np.isDefn, prep.takesDet> of {
|
|
<True,True> => prep.s ! Definite ++ np.s ! NPCPrep ; -- fit-triq
|
|
<True,False> => prep.s ! Definite ++ np.s ! NPNom ; -- fuq it-triq
|
|
<False,_> => prep.s ! Indefinite ++ np.s ! NPNom -- fi triq
|
|
}
|
|
} ;
|
|
|
|
Compl : Type = Preposition ** {isPresent : 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
|
|
-- 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 + "ħ" ;
|
|
_ => s
|
|
} ;
|
|
ftahni : Str = case s of {
|
|
ftahn + "a" => ftahn + "i" ;
|
|
_ => ftahnie
|
|
} ;
|
|
in {
|
|
s1 = ftahna ; s2 = ftahnie ; s3 = ftahni ;
|
|
} ;
|
|
|
|
stemVariantsImpf : Str -> VerbStems = \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 => VerbStems) = \tbl ->
|
|
\\vf => case vf of {
|
|
VPerf _ => stemVariantsPerf (tbl ! vf) ;
|
|
VImpf _ => stemVariantsImpf (tbl ! vf) ;
|
|
_ => mkVerbStems (tbl ! vf)
|
|
} ;
|
|
|
|
Verb : Type = {
|
|
s : VForm => VerbStems ; --- need to store different "stems" already at verb level (ġera/ġerie/ġeri)
|
|
i : VerbInfo ;
|
|
hasPresPart : Bool ;
|
|
hasPastPart : Bool ;
|
|
} ;
|
|
|
|
VerbInfo : Type = {
|
|
class : VClass ;
|
|
form : VDerivedForm ;
|
|
root : Root ; -- radicals
|
|
patt : Pattern ; -- vowels extracted from mamma
|
|
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
|
|
| VPresPart GenNum -- Present/active particible, e.g. RIEQED
|
|
| VPastPart GenNum -- Passive/past particible, e.g. MAĦBUB
|
|
;
|
|
|
|
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
|
|
|
|
--- TEMP FUNCTION
|
|
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 <tense,ant,pol> of {
|
|
<Pres,Simul,Pos> => b1 (verb.s ! VImpf vagr) ; -- norqod
|
|
<Pres,Simul,Neg> => b2 ma (verb.s ! VImpf vagr) ; -- ma norqodx
|
|
|
|
<Past,Simul,Pos> => b1 (verb.s ! VPerf vagr) ; -- rqadt
|
|
<Past,Simul,Neg> => b2 ma (verb.s ! VPerf vagr) ; -- ma rqadtx
|
|
|
|
<Fut, Simul,Pos> => b2 "se" (verb.s ! VImpf vagr) ; -- se norqod
|
|
<Fut, Simul,Neg> => b2 (mhux ! vagr ++ "se") (verb.s ! VImpf vagr) ; -- m'iniex se norqod
|
|
|
|
<Cond, _ ,Pos> => b2 kien (verb.s ! VImpf vagr) ; -- kont norqod
|
|
<Cond, _ ,Neg> => b2 (ma ++ kienx) (verb.s ! VImpf vagr) ; -- ma kontx norqod
|
|
|
|
-- Same as Past Simul
|
|
<Pres,Anter,Pos> => b1 (verb.s ! VPerf vagr) ; -- rqadt
|
|
<Pres,Anter,Neg> => b2 ma (verb.s ! VPerf vagr) ; -- ma rqadtx
|
|
|
|
<Past,Anter,Pos> => b2 kien (verb.s ! VPerf vagr) ; -- kont rqadt
|
|
<Past,Anter,Neg> => b2 (ma ++ kienx) (verb.s ! VPerf vagr) ; -- ma kontx rqadt
|
|
|
|
<Fut, Anter,Pos> => b2 ("se" ++ nkun) (verb.s ! VPerf vagr) ; -- se nkun rqadt
|
|
<Fut, Anter,Neg> => 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 <toVAgr dir_a, toVAgr ind_a> of {
|
|
<AgP3Pl, AgP2 Sg> => ind.s3 ; -- hom-lok
|
|
_ => ind.s1 -- hie-lek
|
|
} ;
|
|
ind_neg : Str = case <toVAgr dir_a, toVAgr ind_a> of {
|
|
<AgP3Pl, AgP2 Sg> => ind.s4 ; -- hom-lokx
|
|
_ => ind.s2 -- hie-lekx
|
|
} ;
|
|
in
|
|
case takesAux tense ant of {
|
|
|
|
-- aux is already negated for us
|
|
True => aux ++ case <exists Agr vp.dir, exists Agr vp.ind> of {
|
|
|
|
-- konna ftaħna / ma konniex ftaħna
|
|
<False,False> => stems.s1 ;
|
|
|
|
-- konna ftaħnie-ha / ma konniex ftaħni-ha
|
|
<True ,False> => stems.s2 ++ BIND ++ dir.s1 ;
|
|
|
|
-- konna ftaħnie-lha / ma konniex ftaħni-lha
|
|
<False,True > => stems.s2 ++ BIND ++ ind.s1 ;
|
|
|
|
-- konna ftaħni-hie-lha / ma konniex ftaħni-hi-lha
|
|
<True, True > => stems.s3 ++ BIND ++ dir.s2 ++ BIND ++ ind.s1
|
|
|
|
} ;
|
|
|
|
-- No aux part to handle
|
|
False => aux ++ case isPerf tense ant of {
|
|
|
|
True => case <exists Agr vp.dir, exists Agr vp.ind, pol> of {
|
|
|
|
-- ftaħna / ftaħnie-x
|
|
<False,False,Pos> => stems.s1 ;
|
|
<False,False,Neg> => stems.s2 ++ BIND ++ x ;
|
|
|
|
-- ftaħnie-ha / ftaħni-hie-x
|
|
<True ,False,Pos> => stems.s2 ++ BIND ++ dir.s1 ;
|
|
<True ,False,Neg> => stems.s3 ++ BIND ++ dir.s2 ++ BIND ++ x ;
|
|
|
|
-- ftaħnie-lha / ftaħni-lhie-x
|
|
<False,True ,Pos> => case <sing vagr, femOrPlural ind_a> of {
|
|
<True,True> => stems.s2 ++ BIND ++ ind.s3 ; -- fetħ-ilha
|
|
<False,True> => stems.s2 ++ BIND ++ ind.s1 ; -- ftaħnie-lha
|
|
_ => stems.s1 ++ BIND ++ ind.s1 -- fetaħ-li
|
|
} ;
|
|
<False,True ,Neg> => case <sing vagr, femOrPlural ind_a> of {
|
|
<True,True> => stems.s2 ++ BIND ++ ind.s4 ++ BIND ++ x ; -- fetħ-ilhiex
|
|
<False,True> => 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
|
|
<True, True ,Pos> => stems.s2 ++ BIND ++ dir.s2 ++ BIND ++ ind_pos ;
|
|
<True, True ,Neg> => stems.s3 ++ BIND ++ dir.s3 ++ BIND ++ ind_neg ++ BIND ++ x
|
|
|
|
} ;
|
|
|
|
False => case <exists Agr vp.dir, exists Agr vp.ind, pol> of {
|
|
|
|
-- jiftaħ / jiftaħ-x
|
|
<False,False,Pos> => stems.s1 ;
|
|
<False,False,Neg> => stems.s1 ++ BIND ++ x ;
|
|
|
|
-- jiftaħ-ha / jiftaħ-hie-x
|
|
<True ,False,Pos> => stems.s1 ++ BIND ++ dir.s1 ;
|
|
<True ,False,Neg> => stems.s1 ++ BIND ++ dir.s2 ++ BIND ++ x ;
|
|
|
|
-- jiftħ-ilha / jiftħ-ilhie-x
|
|
<False,True ,Pos> => case <sing vagr, femOrPlural ind_a> of {
|
|
<True,True> => stems.s2 ++ BIND ++ ind.s3 ; -- jiftħ-ilha
|
|
<False,True> => stems.s2 ++ BIND ++ ind.s1 ; -- jiftħu-lha
|
|
_ => stems.s1 ++ BIND ++ ind.s1 -- jiftaħ-li
|
|
} ;
|
|
<False,True ,Neg> => case <sing vagr, femOrPlural ind_a> of {
|
|
<True,True> => stems.s2 ++ BIND ++ ind.s4 ++ BIND ++ x ; -- jiftħ-ilhiex
|
|
<False,True> => 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
|
|
<True, True ,Pos> => stems.s1 ++ BIND ++ dir.s2 ++ BIND ++ ind_pos ;
|
|
<True, True ,Neg> => 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 <tense,ant> of {
|
|
<Pres, Simul> => False ;
|
|
<Past, Simul> => False ;
|
|
<Fut , Simul> => True ;
|
|
<Cond, Simul> => True ;
|
|
<Pres, Anter> => False ;
|
|
<Past, Anter> => True ;
|
|
<Fut , Anter> => True ;
|
|
<Cond, Anter> => True
|
|
} ;
|
|
|
|
-- Does a tense + ant give a perfective verb?
|
|
-- Must match with the logic in pickVerbForm
|
|
isPerf : Tense -> Anteriority -> Bool = \tense,ant ->
|
|
case <tense,ant> of {
|
|
<Pres, Simul> => False ;
|
|
<Past, Simul> => True ;
|
|
<Fut , Simul> => False ;
|
|
<Cond, Simul> => False ;
|
|
<Pres, Anter> => True ;
|
|
<Past, Anter> => True ;
|
|
<Fut , Anter> => True ;
|
|
<Cond, Anter> => 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 : {
|
|
s : VForm => VerbStems ;
|
|
hasPresPart : Bool ;
|
|
hasPastPart : Bool ;
|
|
} ;
|
|
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 <vform,pol> of {
|
|
<VPerf (AgP1 Sg), Pos> => "kont" ;
|
|
<VPerf (AgP2 Sg), Pos> => "kont" ;
|
|
<VPerf (AgP3Sg Masc), Pos> => "kien" ;
|
|
<VPerf (AgP3Sg Fem), Pos> => "kienet" ;
|
|
<VPerf (AgP1 Pl), Pos> => "konna" ;
|
|
<VPerf (AgP2 Pl), Pos> => "kontu" ;
|
|
<VPerf (AgP3Pl), Pos> => "kienu" ;
|
|
<VImpf (AgP1 Sg), Pos> => "nkun" ;
|
|
<VImpf (AgP2 Sg), Pos> => "tkun" ;
|
|
<VImpf (AgP3Sg Masc), Pos> => "jkun" ;
|
|
<VImpf (AgP3Sg Fem), Pos> => "tkun" ;
|
|
<VImpf (AgP1 Pl), Pos> => "nkunu" ;
|
|
<VImpf (AgP2 Pl), Pos> => "tkunu" ;
|
|
<VImpf (AgP3Pl), Pos> => "jkunu" ;
|
|
<VImp (Pl), Pos> => "kun" ;
|
|
<VImp (Sg), Pos> => "kunu" ;
|
|
<VPerf (AgP1 Sg), Neg> => "kontx" ;
|
|
<VPerf (AgP2 Sg), Neg> => "kontx" ;
|
|
<VPerf (AgP3Sg Masc), Neg> => "kienx" ;
|
|
<VPerf (AgP3Sg Fem), Neg> => "kinitx" ;
|
|
<VPerf (AgP1 Pl), Neg> => "konniex" ;
|
|
<VPerf (AgP2 Pl), Neg> => "kontux" ;
|
|
<VPerf (AgP3Pl), Neg> => "kienux" ;
|
|
<VImpf (AgP1 Sg), Neg> => "nkunx" ;
|
|
<VImpf (AgP2 Sg), Neg> => "tkunx" ;
|
|
<VImpf (AgP3Sg Masc), Neg> => "jkunx" ;
|
|
<VImpf (AgP3Sg Fem), Neg> => "tkunx" ;
|
|
<VImpf (AgP1 Pl), Neg> => "nkunux" ;
|
|
<VImpf (AgP2 Pl), Neg> => "tkunux" ;
|
|
<VImpf (AgP3Pl), Neg> => "jkunux" ;
|
|
<VImp (Pl), Neg> => "kunx" ;
|
|
<VImp (Sg), Neg> => "kunux" ;
|
|
<VPresPart gn, _> => NONEXIST ;
|
|
<VPastPart gn, _> => NONEXIST
|
|
}
|
|
} ;
|
|
|
|
-- Adapted from [AZ]
|
|
CopulaVP : VerbPhrase = {
|
|
-- s = \\vpf,ant,pol =>
|
|
-- --- We are ignoring the anteriority
|
|
-- case <vpf, pol> of {
|
|
-- --- Here we are bypassing VerbParts by putting negatives in the stem
|
|
-- -- <VPIndicat Pres vagr, Pos> => mkVerbParts (copula_kien.s ! VImpf vagr ! Pos) [] ; -- jkun
|
|
-- -- <VPIndicat Pres vagr, Neg> => mkVerbParts (copula_kien.s ! VImpf vagr ! Neg) [] ; -- ma jkunx
|
|
-- <VPIndicat Pres vagr, Pos> => mkVerbParts (huwa ! vagr) [] ; -- huwa
|
|
-- <VPIndicat Pres vagr, Neg> => mkVerbParts (mhux ! vagr) [] ; -- m'huwiex
|
|
-- <VPIndicat Past vagr, Pos> => mkVerbParts (copula_kien.s ! VPerf vagr ! Pos) [] ; -- kien
|
|
-- <VPIndicat Past vagr, Neg> => mkVerbParts (copula_kien.s ! VPerf vagr ! Neg) [] ; -- ma kienx
|
|
-- <VPIndicat Fut vagr, Pos> => mkVerbParts ("se" ++ copula_kien.s ! VImpf vagr ! Pos) [] ; -- se jkun
|
|
-- <VPIndicat Fut vagr, Neg> => mkVerbParts (mhux ! vagr ++ "se" ++ copula_kien.s ! VImpf vagr ! Pos) [] ; -- mhux se jkun
|
|
-- <VPIndicat Cond vagr, Pos> => mkVerbParts ("kieku" ++ copula_kien.s ! VPerf vagr ! Pos) [] ; -- kieku kien
|
|
-- <VPIndicat Cond vagr, Neg> => mkVerbParts ("kieku" ++ "ma" ++ copula_kien.s ! VPerf vagr ! Neg) [] ; -- kieku ma kienx
|
|
-- <VPImperat num, Pos> => mkVerbParts (copula_kien.s ! VImp num ! Pos) [] ; -- kun
|
|
-- <VPImperat num, Neg> => 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 (Pl) => mkVerbStems "kun" ;
|
|
VImp (Sg) => mkVerbStems "kunu" ;
|
|
VPresPart gn => mkVerbStems NONEXIST ;
|
|
VPastPart gn => mkVerbStems NONEXIST
|
|
} ;
|
|
i = mkVerbInfo Irregular FormI ;
|
|
hasPresPart = False ;
|
|
hasPastPart = False ;
|
|
} ;
|
|
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 perfective
|
|
infVP : VerbPhrase -> Anteriority -> Polarity -> Agr -> Str = \vp,ant,pol,agr ->
|
|
joinVP vp Past ant pol agr ++ vp.s2 ! agr ;
|
|
|
|
Aux = {
|
|
s : Tense => Polarity => Str ;
|
|
} ;
|
|
auxHemm : Aux = {
|
|
s = \\t,p => case <t,p> of {
|
|
<Pres,Pos> => "hemm" ;
|
|
<Pres,Neg> => "m'hemmx" ;
|
|
<Past,Pos> => "kien hemm" ;
|
|
<Past,Neg> => "ma kienx hemm" ;
|
|
<Fut,Pos> => "ħa jkun hemm" ;
|
|
<Fut,Neg> => "mhux ħa jkun hemm" ;
|
|
<Cond,Pos> => "jekk hemm" ;
|
|
<Cond,Neg> => "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"
|
|
} ;
|
|
|
|
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 & 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 ; imp=[] } ;
|
|
mkVerbInfo : VClass -> VDerivedForm -> Str -> VerbInfo = \c,f,i ->
|
|
{ class=c ; form=f ; root=mkRoot ; patt=mkPattern ; imp=i } ;
|
|
mkVerbInfo : VClass -> VDerivedForm -> Root -> Pattern -> VerbInfo = \c,f,r,p ->
|
|
{ class=c ; form=f ; root=r ; patt=p ; imp=[] } ;
|
|
mkVerbInfo : VClass -> VDerivedForm -> Root -> Pattern -> Str -> VerbInfo = \c,f,r,p,i ->
|
|
{ class=c ; form=f ; root=r ; patt=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 ; imp=i.imp } ;
|
|
|
|
-- DerivedForm
|
|
updateVerbInfo : VerbInfo -> VDerivedForm -> VerbInfo = \i,f ->
|
|
{ class=i.class ; form=f ; root=i.root ; patt=i.patt ; imp=i.imp } ;
|
|
|
|
-- DerivedForm, Imperative
|
|
updateVerbInfo : VerbInfo -> VDerivedForm -> Str -> VerbInfo = \i,f,imp ->
|
|
{ class=i.class ; form=f ; root=i.root ; patt=i.patt ; imp=imp } ;
|
|
|
|
} ;
|
|
|
|
{- ~~~ Useful helper functions ~~~ -}
|
|
|
|
NONEXIST : Str = "#NONEXIST#" ;
|
|
|
|
-- 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 <p,s> of {
|
|
<_, ""> => [] ;
|
|
<"", str> => str ;
|
|
<px, str> => px + str
|
|
} ;
|
|
|
|
-- Add suffix, avoiding triple letters {GO pg96-7}
|
|
--- add more cases?
|
|
--- potentially slow
|
|
sfx : Str -> Str -> Str = \a,b ->
|
|
case <a,takePfx 1 b> of {
|
|
<"",_> => [] ;
|
|
<ke+"nn","n"> => ke+"n"+b ;
|
|
<ha+"kk","k"> => ha+"k"+b ;
|
|
<ho+"ll","l"> => ho+"l"+b ;
|
|
<si+"tt","t"> => si+"t"+b ;
|
|
<be+"xx","x"> => 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 = [] ; --- 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" }
|
|
} ;
|
|
|
|
}
|