-- 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.Numeral.KA.Rules
  ( rules
  ) where

import Control.Applicative ((<|>))
import Data.HashMap.Strict (HashMap)
import Data.Maybe
import Data.String
import Data.Text (Text)
import Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text

import Duckling.Dimensions.Types
import Duckling.Numeral.Helpers
import Duckling.Numeral.Types (NumeralData (..))
import Duckling.Regex.Types
import Duckling.Types
import qualified Duckling.Numeral.Types as TNumeral

zeroNineteenMap :: HashMap Text Integer
zeroNineteenMap :: HashMap Text Integer
zeroNineteenMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ ( Text
"ნოლ"       , Integer
0  )
  , ( Text
"ნულ"       , Integer
0  )
  , ( Text
"ნული"      , Integer
0  )
  , ( Text
"ნოლ"       , Integer
0  )
  , ( Text
"ნოლი"      , Integer
0  )
  , ( Text
"ერთი"      , Integer
1  )
  , ( Text
"ორი"       , Integer
2  )
  , ( Text
"ორ"        , Integer
2  )
  , ( Text
"სამი"      , Integer
3  )
  , ( Text
"სამ"       , Integer
3  )
  , ( Text
"ოთხი"      , Integer
4  )
  , ( Text
"ოთხ"       , Integer
4  )
  , ( Text
"ხუთი"      , Integer
5  )
  , ( Text
"ხუთ"       , Integer
5  )
  , ( Text
"ექვსი"     , Integer
6  )
  , ( Text
"ექვს"      , Integer
6  )
  , ( Text
"შვიდი"     , Integer
7  )
  , ( Text
"შვიდ"      , Integer
7  )
  , ( Text
"რვა"       , Integer
8  )
  , ( Text
"რვ"        , Integer
8  )
  , ( Text
"ცხრა"      , Integer
9  )
  , ( Text
"ცხრ"       , Integer
9  )
  , ( Text
"ათი"       , Integer
10 )
  , ( Text
"აათი"      , Integer
10 )
  , ( Text
"თერთმეტი"  , Integer
11 )
  , ( Text
"თერთმეტ"   , Integer
11 )
  , ( Text
"თორმეტი"   , Integer
12 )
  , ( Text
"თორმეტ"    , Integer
12 )
  , ( Text
"ცამეტი"    , Integer
13 )
  , ( Text
"ცამეტ"     , Integer
13 )
  , ( Text
"თოთხმეტი"  , Integer
14 )
  , ( Text
"თოთხმეტ"   , Integer
14 )
  , ( Text
"თხუთმეტი"  , Integer
15 )
  , ( Text
"თხუთმეტ"   , Integer
15 )
  , ( Text
"თექვსმეტი" , Integer
16 )
  , ( Text
"თექვსმეტ"  , Integer
16 )
  , ( Text
"ჩვიდმეტი"  , Integer
17 )
  , ( Text
"ჩვიდმეტ"   , Integer
17 )
  , ( Text
"თვრამეტი"  , Integer
18 )
  , ( Text
"თვრამეტ"   , Integer
18 )
  , ( Text
"ცხრამეტი"  , Integer
19 )
  , ( Text
"ცხრამეტ"   , Integer
19 )
  ]

informalMap :: HashMap Text Integer
informalMap :: HashMap Text Integer
informalMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ ( Text
"ერთი"       , Integer
1 )
  , ( Text
"წყვილი"     , Integer
2 )
  , ( Text
"წყვილები"   , Integer
2 )
  , ( Text
"ცოტა"       , Integer
3 )
  , ( Text
"რამდენიმე"  , Integer
3 )
  , ( Text
"რამოდენიმე" , Integer
3 )
  ]

ruleToNineteen :: Rule
ruleToNineteen :: Rule
ruleToNineteen = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (0..19)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(წყვილ(ებ)?ი|ცოტა|რამდენიმე|რამოდენიმე|ნოლი?|ნული?|ერთი|ორი?|სამი?|ოთხი?|ხუთი?|ექვსი?|შვიდი?|რვა|თერთმეტი?|თორმეტი?|ცამეტი?|თოთხმეტი?|თხუთმეტი?|თექვსმეტი?|ჩვიდმეტი?|თვრამეტი?|ცხრამეტი?|ცხრა|ა?ათი)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        let x :: Text
x = Text -> Text
Text.toLower Text
match in
        (Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
x HashMap Text Integer
zeroNineteenMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer) Maybe Token -> Maybe Token -> Maybe Token
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
        (Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
x HashMap Text Integer
informalMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
notOkForAnyTime)
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

tensMap :: HashMap Text Integer
tensMap :: HashMap Text Integer
tensMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ ( Text
"ოცი"         , Integer
20 )
  , ( Text
"ოცდა"        , Integer
20 )
  , ( Text
"ოც"          , Integer
20 )
  , ( Text
"ოცდაათ"      , Integer
30 )
  , ( Text
"ოცდაათი"     , Integer
30 )
  , ( Text
"ორმოც"       , Integer
40 )
  , ( Text
"ორმოცი"      , Integer
40 )
  , ( Text
"ორმოცდა"     , Integer
40 )
  , ( Text
"ორმოცდაათ"   , Integer
50 )
  , ( Text
"ორმოცდაათი"  , Integer
50 )
  , ( Text
"სამოც"       , Integer
60 )
  , ( Text
"სამოცი"      , Integer
60 )
  , ( Text
"სამოცდა"     , Integer
60 )
  , ( Text
"სამოცდაათ"   , Integer
70 )
  , ( Text
"სამოცდაათი"  , Integer
70 )
  , ( Text
"ოთხმოც"      , Integer
80 )
  , ( Text
"ოთხმოცი"     , Integer
80 )
  , ( Text
"ოთხმოცდა"    , Integer
80 )
  , ( Text
"ოთხმოცდაათ"  , Integer
90 )
  , ( Text
"ოთხმოცდაათი" , Integer
90 )
  ]

ruleTens :: Rule
ruleTens :: Rule
ruleTens = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (20..90)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(ოცდაათი?|ორმოცდაათი?|სამოცდაათი?|ოთხმოცდაათი?|ოცდა|ორმოცდა|სამოცდა|ოთხმოცდა|ოცი?|ორმოცი?|სამოცი?|ოთხმოცი?)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (Text -> Text
Text.toLower Text
match) HashMap Text Integer
tensMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

hundredsMap :: HashMap Text Integer
hundredsMap :: HashMap Text Integer
hundredsMap = [(Text, Integer)] -> HashMap Text Integer
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ ( Text
"ასი"      , Integer
100 )
  , ( Text
"ორასი"    , Integer
200 )
  , ( Text
"სამასი"   , Integer
300 )
  , ( Text
"ოთხასი"   , Integer
400 )
  , ( Text
"ხუთასი"   , Integer
500 )
  , ( Text
"ექვსასი"  , Integer
600 )
  , ( Text
"შვიდასი"  , Integer
700 )
  , ( Text
"რვაასი"   , Integer
800 )
  , ( Text
"ცხრაასი"  , Integer
900 )
  , ( Text
"ას"       , Integer
100 )
  , ( Text
"ორას"     , Integer
200 )
  , ( Text
"სამას"    , Integer
300 )
  , ( Text
"ოთხას"    , Integer
400 )
  , ( Text
"ხუთას"    , Integer
500 )
  , ( Text
"ექვსას"   , Integer
600 )
  , ( Text
"შვიდას"   , Integer
700 )
  , ( Text
"რვაას"    , Integer
800 )
  , ( Text
"ცხრაას"   , Integer
900 )
  , ( Text
"ორ ას"    , Integer
200 )
  , ( Text
"სამ ას"   , Integer
300 )
  , ( Text
"ოთხ ას"   , Integer
400 )
  , ( Text
"ხუთ ას"   , Integer
500 )
  , ( Text
"ექვს ას"  , Integer
600 )
  , ( Text
"შვიდ ას"  , Integer
700 )
  , ( Text
"რვა ას"   , Integer
800 )
  , ( Text
"ცხრა ას"  , Integer
900 )
  , ( Text
"ორ ასი"   , Integer
200 )
  , ( Text
"სამ ასი"  , Integer
300 )
  , ( Text
"ოთხ ასი"  , Integer
400 )
  , ( Text
"ხუთ ასი"  , Integer
500 )
  , ( Text
"ექვს ასი" , Integer
600 )
  , ( Text
"შვიდ ასი" , Integer
700 )
  , ( Text
"რვა ასი"  , Integer
800 )
  , ( Text
"ცხრა ასი" , Integer
900 )
  ]

ruleHundreds :: Rule
ruleHundreds :: Rule
ruleHundreds = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (800..900)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(ასი?|ორ ?ასი?|სამ ?ასი?|ოთხ ?ასი?|ხუთ ?ასი?|ექვს ?ასი?|შვიდ ?ასი?|რვა ?ასი?|ცხრა ?ასი?)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> HashMap Text Integer -> Maybe Integer
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup (Text -> Text
Text.toLower Text
match) HashMap Text Integer
hundredsMap Maybe Integer -> (Integer -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Integer -> Maybe Token
integer
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

rulePowersOfTen :: Rule
rulePowersOfTen :: Rule
rulePowersOfTen = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"powers of tens"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(ათასი?|მილიონი?|მილიარდი?)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) -> case Text -> Text
Text.toLower Text
match of
        Text
"ათასი" -> Double -> Maybe Token
double Double
1e3 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Token -> Maybe Token
withGrain Int
3 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
withMultipliable
        Text
"ათას" -> Double -> Maybe Token
double Double
1e3 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Token -> Maybe Token
withGrain Int
3 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
withMultipliable
        Text
"მილიონი"  -> Double -> Maybe Token
double Double
1e6 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Token -> Maybe Token
withGrain Int
6 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
withMultipliable
        Text
"მილიონ"  -> Double -> Maybe Token
double Double
1e6 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Token -> Maybe Token
withGrain Int
6 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
withMultipliable
        Text
"მილიარდი"  -> Double -> Maybe Token
double Double
1e9 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Token -> Maybe Token
withGrain Int
9 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
withMultipliable
        Text
"მილიარდ"  -> Double -> Maybe Token
double Double
1e9 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Token -> Maybe Token
withGrain Int
9 Maybe Token -> (Token -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Token -> Maybe Token
withMultipliable
        Text
_          -> Maybe Token
forall a. Maybe a
Nothing
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleCompositeTens :: Rule
ruleCompositeTens :: Rule
ruleCompositeTens = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 21..99"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
20,Double
40..Double
90]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
20
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral NumeralData{TNumeral.value = tens}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = units}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
tens Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
units
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleCompositeHundreds :: Rule
ruleCompositeHundreds :: Rule
ruleCompositeHundreds = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 100..999"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
100,Double
200..Double
900]
    , [Double] -> PatternItem
oneOf [Double
20,Double
40..Double
90]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
20
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral NumeralData{TNumeral.value = hundreds}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = tens}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = units}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
hundreds Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
tens Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
units
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleCompositeHundredsAndUnits :: Rule
ruleCompositeHundredsAndUnits :: Rule
ruleCompositeHundredsAndUnits = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 100..999"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
100,Double
200..Double
900]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
20
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral NumeralData{TNumeral.value = hundreds}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = units}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
hundreds Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
units
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleCompositeHundredsAndTens :: Rule
ruleCompositeHundredsAndTens :: Rule
ruleCompositeHundredsAndTens = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 100..999"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
100,Double
200..Double
900]
    , [Double] -> PatternItem
oneOf [Double
10,Double
20..Double
90]
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral NumeralData{TNumeral.value = hundreds}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = tens}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
hundreds Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
tens
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDotSpelledOut :: Rule
ruleDotSpelledOut :: Rule
ruleDotSpelledOut = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"one point 2"
  , pattern :: Pattern
pattern =
    [ Dimension NumeralData -> PatternItem
forall a. Typeable a => Dimension a -> PatternItem
dimension Dimension NumeralData
Numeral
    , String -> PatternItem
regex String
"წერტილი|მთელი"
    , Predicate -> PatternItem
Predicate (Predicate -> PatternItem) -> Predicate -> PatternItem
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (Bool -> Bool) -> Predicate -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Predicate
hasGrain
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral a
nd1:Token
_:Token Dimension a
Numeral a
nd2:[Token]
_) ->
        Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ NumeralData -> Double
TNumeral.value a
NumeralData
nd1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double -> Double
decimalsToDouble (NumeralData -> Double
TNumeral.value a
NumeralData
nd2)
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleLeadingDotSpelledOut :: Rule
ruleLeadingDotSpelledOut :: Rule
ruleLeadingDotSpelledOut = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"point 77"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"წერტილი|მთელი"
    , Predicate -> PatternItem
Predicate (Predicate -> PatternItem) -> Predicate -> PatternItem
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (Bool -> Bool) -> Predicate -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Predicate
hasGrain
    ]
  , prod :: Production
prod = \case
      (Token
_:Token Dimension a
Numeral a
nd:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token)
-> (Double -> Double) -> Double -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Double
decimalsToDouble (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ NumeralData -> Double
TNumeral.value a
NumeralData
nd
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDecimals :: Rule
ruleDecimals :: Rule
ruleDecimals = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"decimal number"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d*\\.\\d+)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) -> Bool -> Text -> Maybe Token
parseDecimal Bool
True Text
match
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleCommas :: Rule
ruleCommas :: Rule
ruleCommas = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"comma-separated numbers"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d+(,\\d\\d\\d)+(\\.\\d+)?)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
RegexMatch (GroupMatch (match:_)):[Token]
_) ->
        Text -> Maybe Double
parseDouble (Text -> Text -> Text -> Text
Text.replace Text
"," Text
Text.empty Text
match) Maybe Double -> (Double -> Maybe Token) -> Maybe Token
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Double -> Maybe Token
double
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleSuffixes :: Rule
ruleSuffixes :: Rule
ruleSuffixes = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"suffixes (K,M,G))"
  , pattern :: Pattern
pattern =
    [ Dimension NumeralData -> PatternItem
forall a. Typeable a => Dimension a -> PatternItem
dimension Dimension NumeralData
Numeral
    , String -> PatternItem
regex String
"(k|m|g)(?=[\\W$€¢£]|$)"
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral a
nd : Token Dimension a
RegexMatch (GroupMatch (match : _)):[Token]
_) -> do
        Double
x <- case Text -> Text
Text.toLower Text
match of
          Text
"k" -> Double -> Maybe Double
forall a. a -> Maybe a
Just Double
1e3
          Text
"m" -> Double -> Maybe Double
forall a. a -> Maybe a
Just Double
1e6
          Text
"g" -> Double -> Maybe Double
forall a. a -> Maybe a
Just Double
1e9
          Text
_ -> Maybe Double
forall a. Maybe a
Nothing
        Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ NumeralData -> Double
TNumeral.value a
NumeralData
nd Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
x
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleNegative :: Rule
ruleNegative :: Rule
ruleNegative = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"negative numbers"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(-|მინუს|მინ)(?!\\s*-)"
    , Predicate -> PatternItem
Predicate Predicate
isPositive
    ]
  , prod :: Production
prod = \case
      (Token
_:Token Dimension a
Numeral a
nd:[Token]
_) -> Double -> Maybe Token
double (NumeralData -> Double
TNumeral.value a
NumeralData
nd Double -> Double -> Double
forall a. Num a => a -> a -> a
* (-Double
1))
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleSum :: Rule
ruleSum :: Rule
ruleSum = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"intersect 2 numbers"
  , pattern :: Pattern
pattern =
    [ Predicate -> PatternItem
Predicate (Predicate -> PatternItem) -> Predicate -> PatternItem
forall a b. (a -> b) -> a -> b
$ [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> (Token -> [Bool]) -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Predicate] -> Token -> [Bool]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Predicate
hasGrain, Predicate
isPositive]
    , Predicate -> PatternItem
Predicate (Predicate -> PatternItem) -> Predicate -> PatternItem
forall a b. (a -> b) -> a -> b
$ [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> (Token -> [Bool]) -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Predicate] -> Token -> [Bool]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Bool -> Bool
not (Bool -> Bool) -> Predicate -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Predicate
isMultipliable, Predicate
isPositive]
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = val2}:
       [Token]
_) | (Double
10 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
g) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
val2 -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
val1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
val2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleSumAnd :: Rule
ruleSumAnd :: Rule
ruleSumAnd = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"intersect 2 numbers (with and)"
  , pattern :: Pattern
pattern =
    [ Predicate -> PatternItem
Predicate (Predicate -> PatternItem) -> Predicate -> PatternItem
forall a b. (a -> b) -> a -> b
$ [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> (Token -> [Bool]) -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Predicate] -> Token -> [Bool]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Predicate
hasGrain, Predicate
isPositive]
    , String -> PatternItem
regex String
"და"
    , Predicate -> PatternItem
Predicate (Predicate -> PatternItem) -> Predicate -> PatternItem
forall a b. (a -> b) -> a -> b
$ [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> (Token -> [Bool]) -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Predicate] -> Token -> [Bool]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [Bool -> Bool
not (Bool -> Bool) -> Predicate -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Predicate
isMultipliable, Predicate
isPositive]
    ]
  , prod :: Production
prod = \case
      (Token Dimension a
Numeral NumeralData{TNumeral.value = val1, TNumeral.grain = Just g}:
       Token
_:
       Token Dimension a
Numeral NumeralData{TNumeral.value = val2}:
       [Token]
_) | (Double
10 Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
g) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
val2 -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
val1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
val2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleMultiply :: Rule
ruleMultiply :: Rule
ruleMultiply = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"compose by multiplication"
  , pattern :: Pattern
pattern =
    [ Dimension NumeralData -> PatternItem
forall a. Typeable a => Dimension a -> PatternItem
dimension Dimension NumeralData
Numeral
    , Predicate -> PatternItem
Predicate Predicate
isMultipliable
    ]
  , prod :: Production
prod = \case
      (Token
token1:Token
token2:[Token]
_) -> Token -> Token -> Maybe Token
multiply Token
token1 Token
token2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

rules :: [Rule]
rules :: [Rule]
rules =
  [ Rule
ruleToNineteen
  , Rule
ruleHundreds
  , Rule
ruleCompositeHundreds
  , Rule
ruleCompositeHundredsAndUnits
  , Rule
ruleCompositeHundredsAndTens
  , Rule
ruleTens
  , Rule
rulePowersOfTen
  , Rule
ruleCompositeTens
  , Rule
ruleDotSpelledOut
  , Rule
ruleLeadingDotSpelledOut
  , Rule
ruleDecimals
  , Rule
ruleCommas
  , Rule
ruleSuffixes
  , Rule
ruleNegative
  , Rule
ruleSum
  , Rule
ruleSumAnd
  , Rule
ruleMultiply
  ]