-- 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. An additional grant -- of patent rights can be found in the PATENTS file in the same directory. {-# LANGUAGE GADTs #-} {-# LANGUAGE NoRebindableSyntax #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Time.VI.Rules ( rules ) where import Control.Monad (liftM2) import Prelude import qualified Data.Text as Text import Duckling.Dimensions.Types import Duckling.Numeral.Helpers (parseInt) import Duckling.Numeral.Types (NumeralData(..)) import Duckling.Ordinal.Types (OrdinalData(..)) import Duckling.Regex.Types import Duckling.Time.Helpers import Duckling.Time.Types (TimeData (..)) import Duckling.Types import qualified Duckling.Numeral.Types as TNumeral import qualified Duckling.Ordinal.Types as TOrdinal import qualified Duckling.Time.Types as TTime import qualified Duckling.TimeGrain.Types as TG ruleTtDng :: Rule ruleTtDng = Rule { name = "tết dương" , pattern = [ regex "(t(\x1ebf)t d(\x01b0)(\x01a1)ng)(l(\x1ecb)ch)?" ] , prod = \_ -> tt $ monthDay 1 1 } ruleNamedday :: Rule ruleNamedday = Rule { name = "named-day" , pattern = [ regex "th(\x1ee9) (2|hai)" ] , prod = \_ -> tt $ dayOfWeek 1 } ruleDayofmonthNamedmonth :: Rule ruleDayofmonthNamedmonth = Rule { name = "<day-of-month> (numeric with day symbol) <named-month>" , pattern = [ regex "(ng(\x00e0)y|m(\x1ed3)ng)( m(\x1ed3)ng)?" , Predicate isDOMInteger , Predicate isAMonth ] , prod = \tokens -> case tokens of (_:token:Token Time td:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleDayofweekCuiCngCaTime :: Rule ruleDayofweekCuiCngCaTime = Rule { name = "<day-of-week> cuối cùng của <time>" , pattern = [ Predicate isADayOfWeek , regex "cu(\x1ed1)i c(\x00f9)ng|cu(\x1ed1)i" , regex "c(\x1ee7)a|trong|v(\x00e0)o" , dimension Time ] , prod = \tokens -> case tokens of (Token Time td1:_:_:Token Time td2:_) -> tt $ predLastOf td1 td2 _ -> Nothing } ruleTimeTi :: Rule ruleTimeTi = Rule { name = "<time> tới" , pattern = [ Predicate isNotLatent , regex "t(\x1edb)i" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 True td _ -> Nothing } ruleCycleCuiCngCaTime :: Rule ruleCycleCuiCngCaTime = Rule { name = "<cycle> cuối cùng của <time>" , pattern = [ dimension TimeGrain , regex "cu(\x1ed1)i c(\x00f9)ng|cu(\x1ed1)i" , regex "c(\x1ee7)a|trong|v(\x00e0)o" , dimension Time ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_:_:Token Time td:_) -> tt $ cycleLastOf grain td _ -> Nothing } ruleNamedmonth12 :: Rule ruleNamedmonth12 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng m(\x01b0)(\x1edd)i hai" ] , prod = \_ -> tt $ month 12 } ruleTimeofdayLatent2 :: Rule ruleTimeofdayLatent2 = Rule { name = "time-of-day (latent)" , pattern = [ regex "(l(\x00fa)c|v(\x00e0)o)( l(\x00fa)c)?" , Predicate $ isIntegerBetween 0 23 ] , prod = \tokens -> case tokens of (_:token:_) -> do v <- getIntValue token tt . mkLatent $ hour False v _ -> Nothing } ruleCchMngThng :: Rule ruleCchMngThng = Rule { name = "cách mạng tháng 8" , pattern = [ regex "c(\x00e1)ch m(\x1ea1)ng th(\x00e1)ng (8|t(\x00e1)m)" ] , prod = \_ -> tt $ monthDay 8 19 } ruleNamedday2 :: Rule ruleNamedday2 = Rule { name = "named-day" , pattern = [ regex "th(\x1ee9) (3|ba)" ] , prod = \_ -> tt $ dayOfWeek 2 } ruleTimeofdayGiNg :: Rule ruleTimeofdayGiNg = Rule { name = "<time-of-day> giờ đúng" , pattern = [ Predicate isATimeOfDay , regex "gi(\x1edd) (\x0111)(\x00fa)ng" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleNamedday6 :: Rule ruleNamedday6 = Rule { name = "named-day" , pattern = [ regex "th(\x1ee9) (7|b((\x1ea3)|(\x1ea9))y)" ] , prod = \_ -> tt $ dayOfWeek 6 } rulePartofdayHmNay :: Rule rulePartofdayHmNay = Rule { name = "<part-of-day> (hôm )?nay" , pattern = [ Predicate isAPartOfDay , regex "(h(\x00f4)m )?nay" ] , prod = \tokens -> case tokens of (Token Time td:_) -> Token Time . partOfDay <$> intersect (cycleNth TG.Day 0) td _ -> Nothing } ruleNamedmonth7 :: Rule ruleNamedmonth7 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng b(\x1ea3)y" ] , prod = \_ -> tt $ month 7 } ruleNgyDdmmyyyy :: Rule ruleNgyDdmmyyyy = Rule { name = "ngày dd/mm/yyyy" , pattern = [ regex "ng(\x00e0)y" , regex "(3[01]|[12]\\d|0?[1-9])[-/](0?[1-9]|1[0-2])[/-](\\d{2,4})" ] , prod = \tokens -> case tokens of (_:Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do y <- parseInt m3 m <- parseInt m2 d <- parseInt m1 tt $ yearMonthDay y m d _ -> Nothing } ruleNamedday4 :: Rule ruleNamedday4 = Rule { name = "named-day" , pattern = [ regex "th(\x1ee9) (5|n(\x0103)m)" ] , prod = \_ -> tt $ dayOfWeek 4 } rulePartofdayTime :: Rule rulePartofdayTime = Rule { name = "<part-of-day> <time>" , pattern = [ Predicate isAPartOfDay , dimension Time ] , prod = \tokens -> case tokens of (Token Time td1:Token Time td2:_) -> Token Time <$> intersect td1 td2 _ -> Nothing } ruleQuarterNumber :: Rule ruleQuarterNumber = Rule { name = "quarter <number>" , pattern = [ Predicate $ isGrain TG.Quarter , dimension Numeral ] , prod = \tokens -> case tokens of (_:token:_) -> do n <- getIntValue token tt . cycleNthAfter True TG.Quarter (n - 1) $ cycleNth TG.Year 0 _ -> Nothing } ruleSeason4 :: Rule ruleSeason4 = Rule { name = "season" , pattern = [ regex "m(\x00f9)a? xu(\x00e2)n" ] , prod = \_ -> Token Time <$> interval TTime.Open (monthDay 3 20) (monthDay 6 21) } ruleNoon :: Rule ruleNoon = Rule { name = "noon" , pattern = [ regex "(bu(\x1ed5)i )?(t(\x1ed1)i|(\x0111)(\x00ea)m)" ] , prod = \_ -> tt $ hour False 12 } ruleQucTLaoNg :: Rule ruleQucTLaoNg = Rule { name = "quốc tế lao động" , pattern = [ regex "(ng(\x00e0)y )?qu(\x1ed1)c t(\x1ebf) lao (\x0111)(\x00f4)ng" ] , prod = \_ -> tt $ monthDay 5 1 } ruleNextCycle :: Rule ruleNextCycle = Rule { name = "next <cycle>" , pattern = [ dimension TimeGrain , regex "(t(\x1edb)i|k(\x1ebf)|sau|ti(\x1ebf)p)( theo)?( ti(\x1ebf)p)?" ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_) -> tt $ cycleNth grain 1 _ -> Nothing } ruleNamedmonth :: Rule ruleNamedmonth = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng (gi(\x00ea)ng|m(\x1ed9)t)" ] , prod = \_ -> tt $ month 1 } ruleTimeofdayApproximately :: Rule ruleTimeofdayApproximately = Rule { name = "<time-of-day> approximately" , pattern = [ Predicate isATimeOfDay , regex "g(\x1ea7)n" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleQuarterNumberOfYear :: Rule ruleQuarterNumberOfYear = Rule { name = "quarter <number> of <year>" , pattern = [ Predicate $ isGrain TG.Quarter , dimension Numeral , regex "c(\x1ee7)a|trong" , dimension Time ] , prod = \tokens -> case tokens of (_:token:_:Token Time td:_) -> do n <- getIntValue token tt $ cycleNthAfter False TG.Quarter (n - 1) td _ -> Nothing } ruleNamedmonth3 :: Rule ruleNamedmonth3 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng ba" ] , prod = \_ -> tt $ month 3 } ruleLunch :: Rule ruleLunch = Rule { name = "lunch" , pattern = [ regex "(bu(\x1ed5)i )?tr(\x01b0)a" ] , prod = \_ -> Token Time . partOfDay . mkLatent <$> interval TTime.Open (hour False 12) (hour False 14) } ruleLastCycle :: Rule ruleLastCycle = Rule { name = "last <cycle>" , pattern = [ dimension TimeGrain , regex "tr(\x01b0)(\x1edb)c|qua|v(\x1eeb)a r(\x1ed3)i|ngo(\x00e1)i" ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_) -> tt . cycleNth grain $ - 1 _ -> Nothing } ruleDdmm :: Rule ruleDdmm = Rule { name = "dd/mm" , pattern = [ regex "(3[01]|[12]\\d|0?[1-9])/(0?[1-9]|1[0-2])" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (dd:mm:_)):_) -> do d <- parseInt dd m <- parseInt mm tt $ monthDay m d _ -> Nothing } ruleAfternoon :: Rule ruleAfternoon = Rule { name = "afternoon" , pattern = [ regex "(bu(\x1ed5)i )?chi(\x1ec1)u" ] , prod = \_ -> Token Time . partOfDay . mkLatent <$> interval TTime.Open (hour False 12) (hour False 19) } ruleNamedmonth4 :: Rule ruleNamedmonth4 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng t(\x01b0)|th(\x00e1)ng b(\x1ed1)n" ] , prod = \_ -> tt $ month 4 } ruleHmNay :: Rule ruleHmNay = Rule { name = "hôm nay" , pattern = [ regex "((ngay )?h(\x00f4)m|b(\x1eef)a) nay" ] , prod = \_ -> tt $ cycleNth TG.Day 0 } ruleAtHhmm :: Rule ruleAtHhmm = Rule { name = "at hh:mm" , pattern = [ regex "(l(\x00fa)c|v(\x00e0)o)( l(\x00fa)c)?" , regex "((?:[01]?\\d)|(?:2[0-3]))[:.hg]([0-5]\\d)" ] , prod = \tokens -> case tokens of (_:Token RegexMatch (GroupMatch (hh:mm:_)):_) -> do h <- parseInt hh m <- parseInt mm tt $ hourMinute True h m _ -> Nothing } ruleHourofdayInteger :: Rule ruleHourofdayInteger = Rule { name = "<hour-of-day> <integer>" , pattern = [ Predicate isAnHourOfDay , Predicate $ isIntegerBetween 1 59 ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}: token: _) -> do n <- getIntValue token tt $ hourMinute is12H hours n _ -> Nothing } ruleHourofdayQuarter :: Rule ruleHourofdayQuarter = Rule { name = "(hour-of-day) quarter" , pattern = [ Predicate isAnHourOfDay , regex "k(\x00e9)m" , Predicate $ isIntegerBetween 1 59 ] , prod = \tokens -> case tokens of (Token Time td:_:token:_) -> do n <- getIntValue token Token Time <$> minutesBefore n td _ -> Nothing } ruleHourofdayHalf :: Rule ruleHourofdayHalf = Rule { name = "(hour-of-day) half" , pattern = [ Predicate isAnHourOfDay , regex "r(\x01b0)(\x1ee1)i" ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) -> tt $ hourMinute is12H hours 30 _ -> Nothing } ruleHourofdayIntegerPht :: Rule ruleHourofdayIntegerPht = Rule { name = "<hour-of-day> <integer> phút" , pattern = [ Predicate isAnHourOfDay , Predicate $ isIntegerBetween 1 59 , regex "ph(\x00fa)t" ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}: token: _) -> do n <- getIntValue token tt $ hourMinute is12H hours n _ -> Nothing } ruleNamedday5 :: Rule ruleNamedday5 = Rule { name = "named-day" , pattern = [ regex "th(\x1ee9) 6|th(\x1ee9) s(\x00e1)u" ] , prod = \_ -> tt $ dayOfWeek 5 } ruleCuiNm :: Rule ruleCuiNm = Rule { name = "cuối năm" , pattern = [ regex "cu(\x1ed1)i n(\x0103)m" ] , prod = \_ -> tt $ cycleNth TG.Year 1 } ruleQuarterNumberYear :: Rule ruleQuarterNumberYear = Rule { name = "quarter <number> <year>" , pattern = [ Predicate $ isGrain TG.Quarter , dimension Numeral , dimension Time ] , prod = \tokens -> case tokens of (_:token:Token Time td:_) -> do v <- getIntValue token tt $ cycleNthAfter False TG.Quarter (v - 1) td _ -> Nothing } ruleTimeofdayLatent :: Rule ruleTimeofdayLatent = Rule { name = "time-of-day (latent)" , pattern = [ Predicate $ isIntegerBetween 0 23 ] , prod = \tokens -> case tokens of (token:_) -> do n <- getIntValue token tt . mkLatent $ hour True n _ -> Nothing } ruleNamedmonth2 :: Rule ruleNamedmonth2 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng hai" ] , prod = \_ -> tt $ month 2 } ruleExactlyTimeofday :: Rule ruleExactlyTimeofday = Rule { name = "exactly <time-of-day>" , pattern = [ regex "(v(\x00e0)o )?(\x0111)(\x00fa)ng" , Predicate isATimeOfDay ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleNgyHmQua :: Rule ruleNgyHmQua = Rule { name = "ngày hôm qua" , pattern = [ regex "(ng(\x00e0)y )?(h(\x00f4)m )?qua" ] , prod = \_ -> tt . cycleNth TG.Day $ - 1 } ruleSeason3 :: Rule ruleSeason3 = Rule { name = "season" , pattern = [ regex "m(\x00f9)a? (\x0111)(\x00f4)ng" ] , prod = \_ -> Token Time <$> interval TTime.Open (monthDay 12 21) (monthDay 3 20) } ruleSeason :: Rule ruleSeason = Rule { name = "season" , pattern = [ regex "m(\x00f9)a? (h(\x00e8)|h(\x1ea1))" ] , prod = \_ -> Token Time <$> interval TTime.Open (monthDay 6 21) (monthDay 9 23) } ruleDayofmonthNamedmonth2 :: Rule ruleDayofmonthNamedmonth2 = Rule { name = "<day-of-month> <named-month>" , pattern = [ Predicate isDOMInteger , Predicate isAMonth ] , prod = \tokens -> case tokens of (token:Token Time td:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleYearNumericWithYearSymbol :: Rule ruleYearNumericWithYearSymbol = Rule { name = "year (numeric with year symbol)" , pattern = [ regex "n(\x0103)m" , Predicate $ isIntegerBetween 1000 9999 ] , prod = \tokens -> case tokens of (_:token:_) -> do n <- getIntValue token tt $ year n _ -> Nothing } ruleAfterWork :: Rule ruleAfterWork = Rule { name = "after work" , pattern = [ regex "(sau gi(\x1edd) l(\x00e0)m|sau gi(\x1edd) tan t(\x1ea7)m|l(\x00fa)c tan t(\x1ea7)m)" ] , prod = \_ -> do td <- interval TTime.Open (hour False 17) (hour False 21) Token Time . partOfDay . notLatent <$> intersect (cycleNth TG.Day 0) td } ruleLastNCycle :: Rule ruleLastNCycle = Rule { name = "last n <cycle>" , pattern = [ Predicate $ isIntegerBetween 1 9999 , dimension TimeGrain , regex "tr(\x01b0)(\x1edb)c|qua|v(\x1eeb)a r(\x1ed3)i|ngo(\x00e1)i|v(\x1eeb)a qua" ] , prod = \tokens -> case tokens of (token:Token TimeGrain grain:_) -> do n <- getIntValue token tt . cycleN True grain $ - n _ -> Nothing } ruleTimeofdaySharp :: Rule ruleTimeofdaySharp = Rule { name = "<time-of-day> sharp" , pattern = [ Predicate isATimeOfDay , regex "(\x0111)(\x00fa)ng" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleIntersect :: Rule ruleIntersect = Rule { name = "intersect" , pattern = [ Predicate isNotLatent , Predicate isNotLatent ] , prod = \tokens -> case tokens of (Token Time td1:Token Time td2:_) -> Token Time <$> intersect td1 td2 _ -> Nothing } ruleAboutTimeofday :: Rule ruleAboutTimeofday = Rule { name = "about <time-of-day>" , pattern = [ regex "(v(\x00e0)o )?kho(\x1ea3)ng" , Predicate isATimeOfDay ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleLTnhNhn :: Rule ruleLTnhNhn = Rule { name = "lễ tình nhân" , pattern = [ regex "(ng(\x00e0)y )?(l(\x1ec5))? t(\x00ec)nh nh(\x00e2)n" ] , prod = \_ -> tt $ monthDay 2 14 } ruleNamedmonth6 :: Rule ruleNamedmonth6 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng s(\x00e1)u" ] , prod = \_ -> tt $ month 6 } ruleNamedmonth8 :: Rule ruleNamedmonth8 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng t(\x00e1)m" ] , prod = \_ -> tt $ month 8 } ruleCuiThng :: Rule ruleCuiThng = Rule { name = "cuối tháng" , pattern = [ regex "cu(\x1ed1)i th(\x00e1)ng" ] , prod = \_ -> tt $ cycleNth TG.Month 1 } ruleWeekend :: Rule ruleWeekend = Rule { name = "week-end" , pattern = [ regex "(cu(\x1ed1)i|h(\x1ebf)t) tu(\x1ea7)n" ] , prod = \_ -> do fri <- intersect (dayOfWeek 5) (hour False 18) mon <- intersect (dayOfWeek 1) (hour False 0) Token Time <$> interval TTime.Open fri mon } ruleTimeofdaySngchiuti :: Rule ruleTimeofdaySngchiuti = Rule { name = "<time-of-day> sáng|chiều|tối" , pattern = [ Predicate isATimeOfDay , regex "(s(\x00e1)ng|chi(\x1ec1)u|t(\x1ed1)i)" ] , prod = \tokens -> case tokens of (Token Time td:Token RegexMatch (GroupMatch (ap:_)):_) -> tt . timeOfDayAMPM td $ Text.toLower ap == "s\225ng" _ -> Nothing } ruleTimeTrc :: Rule ruleTimeTrc = Rule { name = "<time> trước" , pattern = [ dimension Time , regex "tr(\x01b0)(\x1edb)c|v(\x1eeb)a r(\x1ed3)i" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth (-1) False td _ -> Nothing } ruleTimeofdayGi :: Rule ruleTimeofdayGi = Rule { name = "time-of-day giờ" , pattern = [ Predicate isATimeOfDay , regex "gi(\x1edd)" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleQucKhnh :: Rule ruleQucKhnh = Rule { name = "quốc khánh" , pattern = [ regex "qu(\x1ed1)c kh(\x00e1)nh" ] , prod = \_ -> tt $ monthDay 9 3 } ruleYyyymmdd :: Rule ruleYyyymmdd = Rule { name = "yyyy-mm-dd" , pattern = [ regex "(\\d{2,4})-(0?[1-9]|1[0-2])-(3[01]|[12]\\d|0?[1-9])" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (yy:mm:dd:_)):_) -> do y <- parseInt yy m <- parseInt mm d <- parseInt dd tt $ yearMonthDay y m d _ -> Nothing } ruleIntersectByOfFromS :: Rule ruleIntersectByOfFromS = Rule { name = "intersect by \"of\", \"from\", \"'s\"" , pattern = [ Predicate isNotLatent , regex "c(\x1ee7)a|trong" , Predicate isNotLatent ] , prod = \tokens -> case tokens of (Token Time td1:_:Token Time td2:_) -> Token Time <$> intersect td1 td2 _ -> Nothing } ruleNextNCycle :: Rule ruleNextNCycle = Rule { name = "next n <cycle>" , pattern = [ Predicate $ isIntegerBetween 1 9999 , dimension TimeGrain , regex "(t(\x1edb)i|k(\x1ebf)|sau|ti(\x1ebf)p)( theo)?( ti(\x1ebf)p)?" ] , prod = \tokens -> case tokens of (token:Token TimeGrain grain:_) -> do v <- getIntValue token tt $ cycleN True grain v _ -> Nothing } ruleMorning :: Rule ruleMorning = Rule { name = "morning" , pattern = [ regex "(bu(\x1ed5)i )?s(\x00e1)ng" ] , prod = \_ -> Token Time . partOfDay . mkLatent <$> interval TTime.Open (hour False 4) (hour False 12) } ruleThisCycle :: Rule ruleThisCycle = Rule { name = "this <cycle>" , pattern = [ dimension TimeGrain , regex "nay|n(\x00e0)y|hi(\x1ec7)n t(\x1ea1)i|h(\x00f4)m nay|n(\x0103)m nay" ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_) -> tt $ cycleNth grain 0 _ -> Nothing } ruleNoon2 :: Rule ruleNoon2 = Rule { name = "noon" , pattern = [ regex "(bu(\x1ed5)i )?(t(\x1ed1)i|(\x0111)(\x00ea)m)" ] , prod = \_ -> Token Time . partOfDay . mkLatent <$> interval TTime.Open (hour False 18) (hour False 0) } ruleAfterLunch :: Rule ruleAfterLunch = Rule { name = "after lunch" , pattern = [ regex "(sau|qua) (bu(\x1ed5)i |b(\x1eef)a )?tr(\x01b0)a" ] , prod = \_ -> do td <- interval TTime.Open (hour False 13) (hour False 17) Token Time . partOfDay . notLatent <$> intersect (cycleNth TG.Day 0) td } ruleSeason2 :: Rule ruleSeason2 = Rule { name = "season" , pattern = [ regex "m(\x00f9)a? thu" ] , prod = \_ -> Token Time <$> interval TTime.Open (monthDay 9 23) (monthDay 12 21) } ruleTimeNy :: Rule ruleTimeNy = Rule { name = "<time> này" , pattern = [ dimension Time , regex "n(\x00e0)y|nay" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 False td _ -> Nothing } ruleTimeofdayAmpm :: Rule ruleTimeofdayAmpm = Rule { name = "<time-of-day> am|pm" , pattern = [ Predicate isATimeOfDay , regex "(in the )?([ap])(\\s|\\.)?m?\\.?" ] , prod = \tokens -> case tokens of (Token Time td:Token RegexMatch (GroupMatch (_:ap:_)):_) -> tt . timeOfDayAMPM td $ Text.toLower ap == "a" _ -> Nothing } ruleNgyMai :: Rule ruleNgyMai = Rule { name = "ngày mai" , pattern = [ regex "(ng(\x00e0)y )?mai" ] , prod = \_ -> tt $ cycleNth TG.Day 1 } ruleOrdinalCycleOfTime :: Rule ruleOrdinalCycleOfTime = Rule { name = "<ordinal> <cycle> of <time>" , pattern = [ dimension TimeGrain , dimension Ordinal , regex "c(\x1ee7)a|trong" , dimension Time ] , prod = \tokens -> case tokens of (Token TimeGrain grain:Token Ordinal od:_:Token Time td:_) -> tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td _ -> Nothing } ruleNamedmonth5 :: Rule ruleNamedmonth5 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng n(\x0103)m" ] , prod = \_ -> tt $ month 5 } ruleNamedday7 :: Rule ruleNamedday7 = Rule { name = "named-day" , pattern = [ regex "ch(\x1ee7) nh(\x1ead)t" ] , prod = \_ -> tt $ dayOfWeek 7 } ruleMonthNumericWithMonthSymbol :: Rule ruleMonthNumericWithMonthSymbol = Rule { name = "month (numeric with month symbol)" , pattern = [ regex "th(\x00e1)ng" , Predicate $ isIntegerBetween 1 12 ] , prod = \tokens -> case tokens of (_:token:_) -> do v <- getIntValue token tt $ month v _ -> Nothing } ruleHhmm :: Rule ruleHhmm = Rule { name = "hh:mm" , pattern = [ regex "((?:[01]?\\d)|(?:2[0-3]))[:.hg]([0-5]\\d)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (hh:mm:_)):_) -> do h <- parseInt hh m <- parseInt mm tt $ hourMinute True h m _ -> Nothing } ruleTonight :: Rule ruleTonight = Rule { name = "tonight" , pattern = [ regex "(t(\x1ed1)i|(\x0111)(\x00ea)m)( h(\x00f4)m)? nay" ] , prod = \_ -> do let today = cycleNth TG.Day 0 evening <- interval TTime.Open (hour False 18) (hour False 0) Token Time . partOfDay . notLatent <$> intersect today evening } ruleTimezone :: Rule ruleTimezone = Rule { name = "<time> timezone" , pattern = [ Predicate $ liftM2 (&&) (isGrainFinerThan TG.Day) isNotLatent , regex "\\b(YEKT|YEKST|YAKT|YAKST|WITA|WIT|WIB|WGT|WGST|WFT|WET|WEST|WAT|WAST|VUT|VLAT|VLAST|VET|UZT|UYT|UYST|UTC|ULAT|TVT|TMT|TLT|TKT|TJT|TFT|TAHT|SST|SRT|SGT|SCT|SBT|SAST|SAMT|RET|PYT|PYST|PWT|PST|PONT|PMST|PMDT|PKT|PHT|PHOT|PGT|PETT|PETST|PET|PDT|OMST|OMSST|NZST|NZDT|NUT|NST|NPT|NOVT|NOVST|NFT|NDT|NCT|MYT|MVT|MUT|MST|MSK|MSD|MMT|MHT|MDT|MAWT|MART|MAGT|MAGST|LINT|LHST|LHDT|KUYT|KST|KRAT|KRAST|KGT|JST|IST|IRST|IRKT|IRKST|IRDT|IOT|IDT|ICT|HOVT|HKT|GYT|GST|GMT|GILT|GFT|GET|GAMT|GALT|FNT|FKT|FKST|FJT|FJST|EST|EGT|EGST|EET|EEST|EDT|ECT|EAT|EAST|EASST|DAVT|ChST|CXT|CVT|CST|COT|CLT|CLST|CKT|CHAST|CHADT|CET|CEST|CDT|CCT|CAT|CAST|BTT|BST|BRT|BRST|BOT|BNT|AZT|AZST|AZOT|AZOST|AWST|AWDT|AST|ART|AQTT|ANAT|ANAST|AMT|AMST|ALMT|AKST|AKDT|AFT|AEST|AEDT|ADT|ACST|ACDT)\\b" ] , prod = \tokens -> case tokens of (Token Time td: Token RegexMatch (GroupMatch (tz:_)): _) -> Token Time <$> inTimezone tz td _ -> Nothing } ruleNamedmonth10 :: Rule ruleNamedmonth10 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng m(\x01b0)(\x1edd)i" ] , prod = \_ -> tt $ month 10 } ruleByGi :: Rule ruleByGi = Rule { name = "bây giờ" , pattern = [ regex "(ngay )?(b(\x00e2)y gi(\x1edd)|l(\x00fa)c n(\x00e0)y)" ] , prod = \_ -> tt $ cycleNth TG.Second 0 } ruleNgyDdmm :: Rule ruleNgyDdmm = Rule { name = "ngày dd/mm" , pattern = [ regex "ng(\x00e0)y" , regex "(3[01]|[12]\\d|0?[1-9])/(0?[1-9]|1[0-2])" ] , prod = \tokens -> case tokens of (_:Token RegexMatch (GroupMatch (dd:mm:_)):_) -> do d <- parseInt dd m <- parseInt mm tt $ monthDay m d _ -> Nothing } ruleHhmmMilitaryAmpm :: Rule ruleHhmmMilitaryAmpm = Rule { name = "hhmm (military) am|pm" , pattern = [ regex "((?:1[012]|0?\\d))([0-5]\\d)" , regex "([ap])\\.?m?\\.?" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (hh:mm:_)): Token RegexMatch (GroupMatch (ap:_)): _) -> do h <- parseInt hh m <- parseInt mm tt . timeOfDayAMPM (hourMinute True h m) $ Text.toLower ap == "a" _ -> Nothing } ruleHhmmMilitarySngchiuti :: Rule ruleHhmmMilitarySngchiuti = Rule { name = "hhmm (military) sáng|chiều|tối" , pattern = [ regex "((?:1[012]|0?\\d))([0-5]\\d)" , regex "(s(\x00e1)ng|chi(\x1ec1)u|t(\x1ed1)i)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (hh:mm:_)): Token RegexMatch (GroupMatch (ap:_)): _) -> do h <- parseInt hh m <- parseInt mm tt . timeOfDayAMPM (hourMinute True h m) $ Text.toLower ap == "s\225ng" _ -> Nothing } ruleDdmmyyyy :: Rule ruleDdmmyyyy = Rule { name = "dd/mm/yyyy" , pattern = [ regex "(3[01]|[12]\\d|0?[1-9])[-/](0?[1-9]|1[0-2])[/-](\\d{2,4})" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (dd:mm:yy:_)):_) -> do y <- parseInt yy m <- parseInt mm d <- parseInt dd tt $ yearMonthDay y m d _ -> Nothing } ruleNamedmonth11 :: Rule ruleNamedmonth11 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng m(\x01b0)(\x1edd)i m(\x1ed9)t" ] , prod = \_ -> tt $ month 11 } ruleGingSinh :: Rule ruleGingSinh = Rule { name = "giáng sinh" , pattern = [ regex "(ng(\x00e0)y )(xmas|christmas|gi(\x00e1)ng sinh)?" ] , prod = \_ -> tt $ monthDay 12 25 } ruleNamedday3 :: Rule ruleNamedday3 = Rule { name = "named-day" , pattern = [ regex "th(\x1ee9) 4|th(\x1ee9) b(\x1ed1)n|th(\x1ee9) t(\x01b0)" ] , prod = \_ -> tt $ dayOfWeek 3 } ruleNgyHmKia :: Rule ruleNgyHmKia = Rule { name = "ngày hôm kia" , pattern = [ regex "(ng(\x00e0)y )?h(\x00f4)m kia" ] , prod = \_ -> tt . cycleNth TG.Day $ - 2 } ruleDayofweekTi :: Rule ruleDayofweekTi = Rule { name = "<day-of-week> tới" , pattern = [ Predicate isADayOfWeek , regex "t(\x1edb)i" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 True td _ -> Nothing } ruleNamedmonth9 :: Rule ruleNamedmonth9 = Rule { name = "named-month" , pattern = [ regex "th(\x00e1)ng ch(\x00ed)n" ] , prod = \_ -> tt $ month 9 } ruleHhmmss :: Rule ruleHhmmss = Rule { name = "hh:mm:ss" , pattern = [ regex "((?:[01]?\\d)|(?:2[0-3]))[:.]([0-5]\\d)[:.]([0-5]\\d)" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (hh:mm:ss:_)):_) -> do h <- parseInt hh m <- parseInt mm s <- parseInt ss tt $ hourMinuteSecond True h m s _ -> Nothing } rules :: [Rule] rules = [ ruleAboutTimeofday , ruleAfterLunch , ruleAfterWork , ruleAfternoon , ruleAtHhmm , ruleByGi , ruleCchMngThng , ruleCuiNm , ruleCuiThng , ruleCycleCuiCngCaTime , ruleDayofmonthNamedmonth , ruleDayofmonthNamedmonth2 , ruleDayofweekCuiCngCaTime , ruleDayofweekTi , ruleDdmm , ruleDdmmyyyy , ruleExactlyTimeofday , ruleGingSinh , ruleHhmm , ruleHhmmMilitaryAmpm , ruleHhmmMilitarySngchiuti , ruleHhmmss , ruleHmNay , ruleHourofdayHalf , ruleHourofdayInteger , ruleHourofdayIntegerPht , ruleHourofdayQuarter , ruleIntersect , ruleIntersectByOfFromS , ruleLTnhNhn , ruleLastCycle , ruleLastNCycle , ruleLunch , ruleMonthNumericWithMonthSymbol , ruleMorning , ruleNamedday , ruleNamedday2 , ruleNamedday3 , ruleNamedday4 , ruleNamedday5 , ruleNamedday6 , ruleNamedday7 , ruleNamedmonth , ruleNamedmonth10 , ruleNamedmonth11 , ruleNamedmonth12 , ruleNamedmonth2 , ruleNamedmonth3 , ruleNamedmonth4 , ruleNamedmonth5 , ruleNamedmonth6 , ruleNamedmonth7 , ruleNamedmonth8 , ruleNamedmonth9 , ruleNextCycle , ruleNextNCycle , ruleNgyDdmm , ruleNgyDdmmyyyy , ruleNgyHmKia , ruleNgyHmQua , ruleNgyMai , ruleNoon , ruleNoon2 , ruleOrdinalCycleOfTime , rulePartofdayHmNay , rulePartofdayTime , ruleQuarterNumber , ruleQuarterNumberOfYear , ruleQuarterNumberYear , ruleQucKhnh , ruleQucTLaoNg , ruleSeason , ruleSeason2 , ruleSeason3 , ruleSeason4 , ruleThisCycle , ruleTimeNy , ruleTimeTi , ruleTimeTrc , ruleTimeofdayAmpm , ruleTimeofdayApproximately , ruleTimeofdayGi , ruleTimeofdayGiNg , ruleTimeofdayLatent , ruleTimeofdayLatent2 , ruleTimeofdaySharp , ruleTimeofdaySngchiuti , ruleTimezone , ruleTonight , ruleTtDng , ruleWeekend , ruleYearNumericWithYearSymbol , ruleYyyymmdd ]