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

module Duckling.Numeral.JA.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.Numeral.Types (NumeralData (..))
import Duckling.Regex.Types
import Duckling.Types
import qualified Duckling.Numeral.Types as TNumeral

ruleInteger5 :: Rule
ruleInteger5 :: Rule
ruleInteger5 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (100)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"百"
    ]
  , prod :: Production
prod = \[Token]
_ -> Integer -> Maybe Token
integer Integer
100
  }

ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus :: Rule
ruleNumeralsPrefixWithNegativeOrMinus = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"numbers prefix with -, negative or minus"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"-|マイナス\\s?|負\\s?"
    , Predicate -> PatternItem
Predicate Predicate
isPositive
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (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
  }

ruleInteger10 :: Rule
ruleInteger10 :: Rule
ruleInteger10 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (1000..1999)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"千"
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
1000
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token
_:Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) ->
        Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
1000
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator :: Rule
ruleDecimalWithThousandsSeparator = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"decimal with thousands separator"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d+(,\\d\\d\\d)+\\.\\d+)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (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
  }

ruleInteger15 :: Rule
ruleInteger15 :: Rule
ruleInteger15 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (20000..90000)"
  , pattern :: Pattern
pattern =
    [ Double -> Double -> PatternItem
numberBetween Double
2 Double
10
    , String -> PatternItem
regex String
"万"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
10000
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

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

ruleNumeral :: Rule
ruleNumeral :: Rule
ruleNumeral = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"<number>个"
  , pattern :: Pattern
pattern =
    [ Dimension NumeralData -> PatternItem
forall a. Typeable a => Dimension a -> PatternItem
dimension Dimension NumeralData
Numeral
    , String -> PatternItem
regex String
"个"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token
token:[Token]
_) -> Token -> Maybe Token
forall a. a -> Maybe a
Just Token
token
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger3 :: Rule
ruleInteger3 :: Rule
ruleInteger3 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (20..90)"
  , pattern :: Pattern
pattern =
    [ Double -> Double -> PatternItem
numberBetween Double
2 Double
10
    , String -> PatternItem
regex String
"十"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
10
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger13 :: Rule
ruleInteger13 :: Rule
ruleInteger13 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (10000)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"万"
    ]
  , prod :: Production
prod = \[Token]
_ -> Integer -> Maybe Token
integer Integer
10000
  }

ruleInteger6 :: Rule
ruleInteger6 :: Rule
ruleInteger6 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (100..199)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"百"
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
100
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token
_:Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
100
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger12 :: Rule
ruleInteger12 :: Rule
ruleInteger12 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 2001..9999"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
3000, Double
9000, Double
7000, Double
8000, Double
2000, Double
4000, Double
6000, Double
5000]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
1000
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v1}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = v2}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
v2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG :: Rule
ruleNumeralsSuffixesKMG = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"numbers 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|千|万)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v}:
       Token Dimension a
RegexMatch (GroupMatch (match:_)):
       [Token]
_) -> case Text -> Text
Text.toLower Text
match of
          Text
"k"      -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e3
          Text
"千" -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e3
          Text
"万" -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e4
          Text
"m"      -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e6
          Text
"g"      -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1e9
          Text
_ -> Maybe Token
forall a. Maybe a
Nothing
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger7 :: Rule
ruleInteger7 :: Rule
ruleInteger7 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (200..900)"
  , pattern :: Pattern
pattern =
    [ Double -> Double -> PatternItem
numberBetween Double
2 Double
10
    , String -> PatternItem
regex String
"百"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
100
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger14 :: Rule
ruleInteger14 :: Rule
ruleInteger14 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (10000..19999)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"万"
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
10000
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token
_:Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) ->
        Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
10000
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger8 :: Rule
ruleInteger8 :: Rule
ruleInteger8 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 201..999"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
300, Double
600, Double
500, Double
800, Double
200, Double
900, Double
700, Double
400]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
100
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v1}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = v2}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
v2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger16 :: Rule
ruleInteger16 :: Rule
ruleInteger16 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 20001..99999"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
20000, Double
40000, Double
80000, Double
60000, Double
30000, Double
70000, Double
90000, Double
50000]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
10000
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v1}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = v2}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
v2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger9 :: Rule
ruleInteger9 :: Rule
ruleInteger9 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (1000)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"千"
    ]
  , prod :: Production
prod = \[Token]
_ -> Integer -> Maybe Token
integer Integer
1000
  }

integerMap :: HashMap Text Integer
integerMap :: HashMap Text Integer
integerMap = [(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
1)
  , (Text
"二", Integer
2)
  , (Text
"三", Integer
3)
  , (Text
"四", Integer
4)
  , (Text
"五", Integer
5)
  , (Text
"六", Integer
6)
  , (Text
"七", Integer
7)
  , (Text
"八", Integer
8)
  , (Text
"九", Integer
9)
  , (Text
"十", Integer
10)
  ]

ruleInteger :: Rule
ruleInteger :: Rule
ruleInteger = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (0..10)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(ゼロ|零|一|二|三|四|五|六|七|八|九|十)"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (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
integerMap 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
  }

ruleInteger4 :: Rule
ruleInteger4 :: Rule
ruleInteger4 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer 21..99"
  , pattern :: Pattern
pattern =
    [ [Double] -> PatternItem
oneOf [Double
70, Double
20, Double
60, Double
50, Double
40, Double
90, Double
30, Double
80]
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
10
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v1}:
       Token Dimension a
Numeral NumeralData{TNumeral.value = v2}:
       [Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v1 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
v2
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger2 :: Rule
ruleInteger2 :: Rule
ruleInteger2 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (11..19)"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"十"
    , Double -> Double -> PatternItem
numberBetween Double
1 Double
10
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token
_:Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
10
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleInteger11 :: Rule
ruleInteger11 :: Rule
ruleInteger11 = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer (2000..9000)"
  , pattern :: Pattern
pattern =
    [ Double -> Double -> PatternItem
numberBetween Double
2 Double
10
    , String -> PatternItem
regex String
"千"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (Token Dimension a
Numeral NumeralData{TNumeral.value = v}:[Token]
_) -> Double -> Maybe Token
double (Double -> Maybe Token) -> Double -> Maybe Token
forall a b. (a -> b) -> a -> b
$ Double
v Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
1000
      [Token]
_ -> Maybe Token
forall a. Maybe a
Nothing
  }

ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator :: Rule
ruleIntegerWithThousandsSeparator = Rule :: Text -> Pattern -> Production -> Rule
Rule
  { name :: Text
name = Text
"integer with thousands separator ,"
  , pattern :: Pattern
pattern =
    [ String -> PatternItem
regex String
"(\\d{1,3}(,\\d\\d\\d){1,5})"
    ]
  , prod :: Production
prod = \[Token]
tokens -> case [Token]
tokens of
      (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
  }

rules :: [Rule]
rules :: [Rule]
rules =
  [ Rule
ruleDecimalNumeral
  , Rule
ruleDecimalWithThousandsSeparator
  , Rule
ruleInteger
  , Rule
ruleInteger10
  , Rule
ruleInteger11
  , Rule
ruleInteger12
  , Rule
ruleInteger13
  , Rule
ruleInteger14
  , Rule
ruleInteger15
  , Rule
ruleInteger16
  , Rule
ruleInteger2
  , Rule
ruleInteger3
  , Rule
ruleInteger4
  , Rule
ruleInteger5
  , Rule
ruleInteger6
  , Rule
ruleInteger7
  , Rule
ruleInteger8
  , Rule
ruleInteger9
  , Rule
ruleIntegerWithThousandsSeparator
  , Rule
ruleNumeral
  , Rule
ruleNumeralsPrefixWithNegativeOrMinus
  , Rule
ruleNumeralsSuffixesKMG
  ]