diff --git a/CHANGELOG.md b/CHANGELOG.md index 88ec81d9..3a797c37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ * CA (Catalan) * AmountOfMoney: **new!** * Distance: **new!** + * Duration: **new!** * Temperature: **new!** * Volume: **new!** diff --git a/Duckling/Dimensions/CA.hs b/Duckling/Dimensions/CA.hs index ca2dd372..a2cd4e42 100644 --- a/Duckling/Dimensions/CA.hs +++ b/Duckling/Dimensions/CA.hs @@ -15,6 +15,7 @@ allDimensions :: [Seal Dimension] allDimensions = [ Seal AmountOfMoney , Seal Distance + , Seal Duration , Seal Numeral , Seal Ordinal , Seal Temperature diff --git a/Duckling/Duration/CA/Corpus.hs b/Duckling/Duration/CA/Corpus.hs new file mode 100644 index 00000000..a80dbbdd --- /dev/null +++ b/Duckling/Duration/CA/Corpus.hs @@ -0,0 +1,58 @@ +-- Copyright (c) 2016-present, Facebook, Inc. +-- All rights reserved. +-- +-- This source code is licensed under the BSD-style license found in the +-- LICENSE file in the root directory of this source tree. + + +{-# LANGUAGE OverloadedStrings #-} + +module Duckling.Duration.CA.Corpus + ( corpus + ) where + +import Prelude +import Data.String + +import Duckling.Duration.Types +import Duckling.Locale +import Duckling.Resolve +import Duckling.Testing.Types +import Duckling.TimeGrain.Types (Grain(..)) + +corpus :: Corpus +corpus = (testContext {locale = makeLocale CA Nothing}, testOptions, allExamples) + +allExamples :: [Example] +allExamples = concat + [ examples (DurationData 30 Minute) + [ "mitja hora" + , "dos quarts" + , "30 minuts" + , "trenta minuts" + ] + , examples (DurationData 15 Minute) + [ "quart d'hora" + , "un quart d'hora" + , "1 quart d'hora" + , "1/4 d'hora" + , "quinze minuts" + , "15 minuts" + ] + , examples (DurationData 45 Minute) + [ "tres quarts d'hora" + , "3/4 d'hora" + , "3 quarts d'hora" + , "tres quarts" + , "quaranta-cinc minuts" + , "45 minuts" + ] + , examples (DurationData 92 Minute) + [ "una hora i trenta-dos minuts" + , "una hora trenta-dos minuts" + ] + , examples (DurationData 155 Minute) + [ "dues hores i trenta-cinc minuts" + , "dues hores trenta-cinc minuts" + ] + ] diff --git a/Duckling/Duration/CA/Rules.hs b/Duckling/Duration/CA/Rules.hs new file mode 100644 index 00000000..0d0f43ea --- /dev/null +++ b/Duckling/Duration/CA/Rules.hs @@ -0,0 +1,97 @@ +-- Copyright (c) 2016-present, Facebook, Inc. +-- All rights reserved. +-- +-- This source code is licensed under the BSD-style license found in the +-- LICENSE file in the root directory of this source tree. + + +{-# LANGUAGE GADTs #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NoRebindableSyntax #-} +{-# LANGUAGE OverloadedStrings #-} + +module Duckling.Duration.CA.Rules + ( rules + ) where + +import Prelude +import Duckling.Dimensions.Types +import Duckling.Duration.Helpers +import Duckling.Duration.Types (DurationData(..)) +import Duckling.Numeral.Types (NumeralData(..)) +import Duckling.Types +import qualified Duckling.Duration.Types as TDuration +import qualified Duckling.Numeral.Types as TNumeral +import qualified Duckling.TimeGrain.Types as TG + +ruleDurationQuarterOfAnHour :: Rule +ruleDurationQuarterOfAnHour = Rule + { name = "quarter of an hour" + , pattern = + [ regex "((1 |un )?quarts?|1/4) d'hora" + ] + , prod = \_ -> Just $ Token Duration $ duration TG.Minute 15 + } + +ruleDurationHalfOfAnHour :: Rule +ruleDurationHalfOfAnHour = Rule + { name = "half of an hour" + , pattern = + [ regex "(mitja hora|dos quarts)" + ] + , prod = \_ -> Just $ Token Duration $ duration TG.Minute 30 + } + +ruleDurationThreeQuartersOfAnHour :: Rule +ruleDurationThreeQuartersOfAnHour = Rule + { name = "three-quarters of an hour" + , pattern = + [ regex "((tres|3) quarts|3/4)( d'hor([a]|(es)))?" + ] + , prod = \_ -> Just $ Token Duration $ duration TG.Minute 45 + } + +ruleCompositeDurationCommasAnd :: Rule +ruleCompositeDurationCommasAnd = Rule + { name = "composite (with and)" + , pattern = + [ Predicate isNatural + , dimension TimeGrain + , regex "i" + , dimension Duration + ] + , prod = \case + (Token Numeral NumeralData{TNumeral.value = v}: + Token TimeGrain g: + _: + Token Duration dd@DurationData{TDuration.grain = dg}: + _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd + _ -> Nothing + } + +ruleCompositeDuration :: Rule +ruleCompositeDuration = Rule + { + name = "composite " + , pattern = + [ + Predicate isNatural + , dimension TimeGrain + , dimension Duration + ] + , prod = \case + (Token Numeral NumeralData{TNumeral.value = v}: + Token TimeGrain g: + Token Duration dd@DurationData{TDuration.grain = dg}: + _) | g > dg -> Just $ Token Duration $ duration g (floor v) <> dd + _ -> Nothing + } + +rules :: [Rule] +rules = + [ ruleDurationHalfOfAnHour + , ruleDurationQuarterOfAnHour + , ruleDurationThreeQuartersOfAnHour + , ruleCompositeDuration + , ruleCompositeDurationCommasAnd + ] diff --git a/Duckling/Rules/CA.hs b/Duckling/Rules/CA.hs index e48a25ec..5f11cd4b 100644 --- a/Duckling/Rules/CA.hs +++ b/Duckling/Rules/CA.hs @@ -19,6 +19,7 @@ import Duckling.Dimensions.Types import Duckling.Locale import qualified Duckling.AmountOfMoney.CA.Rules as AmountOfMoney import qualified Duckling.Distance.CA.Rules as Distance +import qualified Duckling.Duration.CA.Rules as Duration import qualified Duckling.Numeral.CA.Rules as Numeral import qualified Duckling.Ordinal.CA.Rules as Ordinal import qualified Duckling.Temperature.CA.Rules as Temperature @@ -37,7 +38,7 @@ langRules :: Seal Dimension -> [Rule] langRules (Seal AmountOfMoney) = AmountOfMoney.rules langRules (Seal CreditCardNumber) = [] langRules (Seal Distance) = Distance.rules -langRules (Seal Duration) = [] +langRules (Seal Duration) = Duration.rules langRules (Seal Email) = [] langRules (Seal Numeral) = Numeral.rules langRules (Seal Ordinal) = Ordinal.rules diff --git a/duckling.cabal b/duckling.cabal index dac7b3d2..06dc0289 100644 --- a/duckling.cabal +++ b/duckling.cabal @@ -346,6 +346,8 @@ library , Duckling.Duration.AR.Rules , Duckling.Duration.BG.Corpus , Duckling.Duration.BG.Rules + , Duckling.Duration.CA.Corpus + , Duckling.Duration.CA.Rules , Duckling.Duration.DA.Rules , Duckling.Duration.DE.Rules , Duckling.Duration.EL.Corpus @@ -966,6 +968,7 @@ test-suite duckling-test -- Duration , Duckling.Duration.AR.Tests , Duckling.Duration.BG.Tests + , Duckling.Duration.CA.Tests , Duckling.Duration.EL.Tests , Duckling.Duration.EN.Tests , Duckling.Duration.ES.Tests diff --git a/tests/Duckling/Duration/CA/Tests.hs b/tests/Duckling/Duration/CA/Tests.hs new file mode 100644 index 00000000..d8b19a40 --- /dev/null +++ b/tests/Duckling/Duration/CA/Tests.hs @@ -0,0 +1,22 @@ +-- Copyright (c) 2016-present, Facebook, Inc. +-- All rights reserved. +-- +-- This source code is licensed under the BSD-style license found in the +-- LICENSE file in the root directory of this source tree. + + +module Duckling.Duration.CA.Tests + ( tests ) where + +import Data.String +import Prelude +import Test.Tasty + +import Duckling.Duration.CA.Corpus +import Duckling.Dimensions.Types +import Duckling.Testing.Asserts + +tests :: TestTree +tests = testGroup "CA Tests" + [ makeCorpusTest [Seal Duration] corpus + ]