-- 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 OverloadedStrings #-}

module Duckling.Quantity.ZH.Rules
  ( rules
  ) where

import Data.HashMap.Strict (HashMap)
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.Quantity.Helpers
import Duckling.Regex.Types
import Duckling.Types
import qualified Duckling.Numeral.Types as TNumeral
import qualified Duckling.Quantity.Types as TQuantity

quantities :: [(Text, String, TQuantity.Unit)]
quantities :: [(Text, String, Unit)]
quantities =
  [ (Text
"<quantity> grams", String
"(千克|公斤|斤|两|兩|克|毫克|kg|g|mg)", Unit
TQuantity.Gram)
  ]

opsMap :: HashMap Text (Double -> Double)
opsMap :: HashMap Text (Double -> Double)
opsMap = [(Text, Double -> Double)] -> HashMap Text (Double -> Double)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList
  [ ( Text
"千克" , (Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1000))
  , ( Text
"公斤",  (Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1000))
  , ( Text
"kg",   (Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1000))
  , ( Text
"斤",    (Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
500))
  , ( Text
"两",    (Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
50))
  , ( Text
"兩",    (Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
50))
  , ( Text
"毫克",  (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1000))
  , ( Text
"mg",   (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1000))
  ]

ruleNumeralQuantities :: [Rule]
ruleNumeralQuantities :: [Rule]
ruleNumeralQuantities = ((Text, String, Unit) -> Rule) -> [(Text, String, Unit)] -> [Rule]
forall a b. (a -> b) -> [a] -> [b]
map (Text, String, Unit) -> Rule
go [(Text, String, Unit)]
quantities
  where
    getValue :: Text -> Double -> Double
    getValue :: Text -> Double -> Double
getValue Text
match = (Double -> Double)
-> Text -> HashMap Text (Double -> Double) -> Double -> Double
forall k v. (Eq k, Hashable k) => v -> k -> HashMap k v -> v
HashMap.lookupDefault Double -> Double
forall a. a -> a
id (Text -> Text
Text.toLower Text
match) HashMap Text (Double -> Double)
opsMap

    go :: (Text, String, TQuantity.Unit) -> Rule
    go :: (Text, String, Unit) -> Rule
go (Text
name, String
regexPattern, Unit
u) = Rule :: Text -> Pattern -> Production -> Rule
Rule
      { name :: Text
name = Text
name
      , pattern :: Pattern
pattern =
        [ Predicate -> PatternItem
Predicate Predicate
isPositive
        , String -> PatternItem
regex String
regexPattern
        ]
      , prod :: Production
prod = \case
        (Token Dimension a
Numeral a
nd:
         Token Dimension a
RegexMatch (GroupMatch (match:_)):
         [Token]
_) -> Token -> Maybe Token
forall a. a -> Maybe a
Just (Token -> Maybe Token)
-> (QuantityData -> Token) -> QuantityData -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension QuantityData -> QuantityData -> Token
forall a.
(Resolve a, Eq a, Hashable a, Show a, NFData a) =>
Dimension a -> a -> Token
Token Dimension QuantityData
Quantity (QuantityData -> Maybe Token) -> QuantityData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Unit -> Double -> QuantityData
quantity Unit
u Double
value
          where value :: Double
value = Text -> Double -> Double
getValue Text
match (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ NumeralData -> Double
TNumeral.value a
NumeralData
nd
        [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
      }

ruleCattyTael :: Rule
ruleCattyTael :: Rule
ruleCattyTael = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"<quantity> catty <quantity> tael"
  , pattern :: Pattern
pattern =
    [ Predicate -> PatternItem
Predicate Predicate
isPositive
    , String -> PatternItem
regex String
"斤"
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
10
    , String -> PatternItem
regex String
"两|兩"
    ]
  , prod :: Production
prod = \case
    (Token Dimension a
Numeral TNumeral.NumeralData{TNumeral.value = x}:
     Token Dimension a
RegexMatch (GroupMatch _):
     Token Dimension a
Numeral TNumeral.NumeralData{TNumeral.value = y}:
     Token Dimension a
RegexMatch (GroupMatch _):
     [Token]
_) -> Token -> Maybe Token
forall a. a -> Maybe a
Just (Token -> Maybe Token)
-> (QuantityData -> Token) -> QuantityData -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension QuantityData -> QuantityData -> Token
forall a.
(Resolve a, Eq a, Hashable a, Show a, NFData a) =>
Dimension a -> a -> Token
Token Dimension QuantityData
Quantity (QuantityData -> Maybe Token) -> QuantityData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Unit -> Double -> QuantityData
quantity Unit
TQuantity.Gram (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
500 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
y Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
50)
    [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleCattyHalf :: Rule
ruleCattyHalf :: Rule
ruleCattyHalf = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"<quantity> catty half"
  , pattern :: Pattern
pattern =
    [ Predicate -> PatternItem
Predicate Predicate
isPositive
    , String -> PatternItem
regex String
"斤半"
    ]
  , prod :: Production
prod = \case
    (Token Dimension a
Numeral TNumeral.NumeralData{TNumeral.value = x}:
     Token Dimension a
RegexMatch (GroupMatch _):
     [Token]
_) -> Token -> Maybe Token
forall a. a -> Maybe a
Just (Token -> Maybe Token)
-> (QuantityData -> Token) -> QuantityData -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension QuantityData -> QuantityData -> Token
forall a.
(Resolve a, Eq a, Hashable a, Show a, NFData a) =>
Dimension a -> a -> Token
Token Dimension QuantityData
Quantity (QuantityData -> Maybe Token) -> QuantityData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Unit -> Double -> QuantityData
quantity Unit
TQuantity.Gram (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
500 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
250)
    [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleTaelHalf :: Rule
ruleTaelHalf :: Rule
ruleTaelHalf = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"<quantity> tael half"
  , pattern :: Pattern
pattern =
    [ Predicate -> PatternItem
Predicate Predicate
isPositive
    , String -> PatternItem
regex String
"(两|兩)半"
    ]
  , prod :: Production
prod = \case
    (Token Dimension a
Numeral TNumeral.NumeralData{TNumeral.value = x}:
     Token Dimension a
RegexMatch (GroupMatch _):
     [Token]
_) -> Token -> Maybe Token
forall a. a -> Maybe a
Just (Token -> Maybe Token)
-> (QuantityData -> Token) -> QuantityData -> Maybe Token
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dimension QuantityData -> QuantityData -> Token
forall a.
(Resolve a, Eq a, Hashable a, Show a, NFData a) =>
Dimension a -> a -> Token
Token Dimension QuantityData
Quantity (QuantityData -> Maybe Token) -> QuantityData -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Unit -> Double -> QuantityData
quantity Unit
TQuantity.Gram (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
50 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
25)
    [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

rules :: [Rule]
rules :: [Rule]
rules =
  [ Rule
ruleCattyTael
  , Rule
ruleCattyHalf
  , Rule
ruleTaelHalf
  ]
  [Rule] -> [Rule] -> [Rule]
forall a. [a] -> [a] -> [a]
++ [Rule]
ruleNumeralQuantities