-- 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 NoRebindableSyntax #-} {-# LANGUAGE OverloadedStrings #-} module Duckling.Time.HE.Rules ( rules ) where import Data.Maybe import Data.String import Data.Text (Text) import Prelude import qualified Data.Text as Text import Duckling.Dimensions.Types import Duckling.Duration.Helpers (isGrain) 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.TimeGrain.Types as TG import qualified Duckling.Time.Types as TTime ruleNextDayofweek :: Rule ruleNextDayofweek = Rule { name = "next <day-of-week>" , pattern = [ Predicate isADayOfWeek , regex "(הבא(ה)?)" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 1 True td _ -> Nothing } ruleNamedday :: Rule ruleNamedday = Rule { name = "ב <named-day>" , pattern = [ regex "ב" , Predicate isADayOfWeek ] , prod = \tokens -> case tokens of (_:x:_) -> Just x _ -> Nothing } ruleAtHourTimeofday :: Rule ruleAtHourTimeofday = Rule { name = "at hour <time-of-day>" , pattern = [ regex "בשעה" , Predicate isATimeOfDay ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleHourofdayAndInteger :: Rule ruleHourofdayAndInteger = Rule { name = "<hour-of-day> and <integer>" , pattern = [ Predicate isAnHourOfDay , regex "ו" , 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 } ruleHourofdayAndQuarter :: Rule ruleHourofdayAndQuarter = Rule { name = "<hour-of-day> and quarter" , pattern = [ Predicate isAnHourOfDay , regex "ו" , regex "רבע(י)?" ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) -> tt $ hourMinute is12H hours 15 _ -> Nothing } ruleHourofdayAndHalf :: Rule ruleHourofdayAndHalf = Rule { name = "<hour-of-day> and half" , pattern = [ Predicate isAnHourOfDay , regex "ו" , regex "חצי|מחצית" ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) -> tt $ hourMinute is12H hours 30 _ -> 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 "רבע(י)?" ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) -> tt $ hourMinute is12H hours 15 _ -> Nothing } ruleHourofdayHalf :: Rule ruleHourofdayHalf = Rule { name = "<hour-of-day> half" , pattern = [ Predicate isAnHourOfDay , regex "חצי|מחצית" ] , prod = \tokens -> case tokens of (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:_) -> tt $ hourMinute is12H hours 30 _ -> Nothing } ruleIntegerTotillbeforeIntegerHourofday :: Rule ruleIntegerTotillbeforeIntegerHourofday = Rule { name = "<integer> to|till|before <integer> (hour-of-day)" , pattern = [ Predicate $ isIntegerBetween 1 59 , regex "לפני|ל" , Predicate isAnHourOfDay ] , prod = \tokens -> case tokens of (token:_:Token Time td:_) -> do n <- getIntValue token Token Time <$> minutesBefore n td _ -> Nothing } ruleQuarterTotillbeforeIntegerHourofday :: Rule ruleQuarterTotillbeforeIntegerHourofday = Rule { name = "quarter to|till|before <integer> (hour-of-day)" , pattern = [ regex "רבע(י)?" , regex "לפני|ל" , Predicate isAnHourOfDay ] , prod = \tokens -> case tokens of (_:_:Token Time td:_) -> Token Time <$> minutesBefore 15 td _ -> Nothing } ruleHalfTotillbeforeIntegerHourofday :: Rule ruleHalfTotillbeforeIntegerHourofday = Rule { name = "half to|till|before <integer> (hour-of-day)" , pattern = [ regex "חצי|מחצית" , regex "לפני|ל" , Predicate isAnHourOfDay ] , prod = \tokens -> case tokens of (_:_:Token Time td:_) -> Token Time <$> minutesBefore 30 td _ -> Nothing } ruleIntegerAfterpastIntegerHourofday :: Rule ruleIntegerAfterpastIntegerHourofday = Rule { name = "integer after|past <integer> (hour-of-day)" , pattern = [ Predicate $ isIntegerBetween 1 59 , regex "אחרי" , Predicate isAnHourOfDay ] , prod = \tokens -> case tokens of (token:_:Token Time td:_) -> do n <- getIntValue token Token Time <$> minutesAfter n td _ -> Nothing } ruleQuarterAfterpastIntegerHourofday :: Rule ruleQuarterAfterpastIntegerHourofday = Rule { name = "quarter after|past <integer> (hour-of-day)" , pattern = [ regex "רבע(י)?" , regex "אחרי" , Predicate isAnHourOfDay ] , prod = \tokens -> case tokens of (_:_:Token Time td:_) -> Token Time <$> minutesAfter 15 td _ -> Nothing } ruleHalfAfterpastIntegerHourofday :: Rule ruleHalfAfterpastIntegerHourofday = Rule { name = "half after|past <integer> (hour-of-day)" , pattern = [ regex "חצי|מחצית" , regex "אחרי" , Predicate isAnHourOfDay ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> Token Time <$> minutesAfter 30 td _ -> Nothing } ruleNamedday2 :: Rule ruleNamedday2 = Rule { name = "named-day" , pattern = [ regex "(יום )?שני" ] , prod = \_ -> tt $ dayOfWeek 1 } ruleSinceTimeofday :: Rule ruleSinceTimeofday = Rule { name = "since <time-of-day>" , pattern = [ regex "מ" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ withDirection TTime.After td _ -> Nothing } ruleLastTime :: Rule ruleLastTime = Rule { name = "last <time>" , pattern = [ dimension Time , regex "שעבר|(ה)?קודם|(ה)?אחרון" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth (-1) False td _ -> Nothing } ruleNamedday6 :: Rule ruleNamedday6 = Rule { name = "named-day" , pattern = [ regex "(יום )?שישי" ] , prod = \_ -> tt $ dayOfWeek 5 } ruleDatetimeDatetimeInterval :: Rule ruleDatetimeDatetimeInterval = Rule { name = "<datetime> - <datetime> (interval)" , pattern = [ Predicate isNotLatent , regex "\\-|ע(ד)?" , Predicate isNotLatent ] , prod = \tokens -> case tokens of (Token Time td1:_:Token Time td2:_) -> Token Time <$> interval TTime.Closed td1 td2 _ -> Nothing } ruleTheDayofmonthNonOrdinal :: Rule ruleTheDayofmonthNonOrdinal = Rule { name = "the <day-of-month> (non ordinal)" , pattern = [ regex "ה/S" , Predicate isDOMInteger ] , prod = \tokens -> case tokens of (_:token:_) -> do n <- getIntValue token tt . mkLatent $ dayOfMonth n _ -> Nothing } ruleCycleAfterTime :: Rule ruleCycleAfterTime = Rule { name = "<cycle> after <time>" , pattern = [ dimension TimeGrain , regex "אחרי" , dimension Time ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_:Token Time td:_) -> tt $ cycleNthAfter False grain 1 td _ -> Nothing } ruleInDuration :: Rule ruleInDuration = Rule { name = "in <duration>" , pattern = [ regex "בעוד" , dimension Duration ] , prod = \tokens -> case tokens of (_:Token Duration dd:_) -> tt $ inDuration dd _ -> Nothing } ruleInNamedmonth :: Rule ruleInNamedmonth = Rule { name = "in <named-month>" , pattern = [ regex "ב" , Predicate isAMonth ] , prod = \tokens -> case tokens of (_:x:_) -> Just x _ -> Nothing } ruleNow :: Rule ruleNow = Rule { name = "now" , pattern = [ regex "עכשיו|מייד" ] , prod = \_ -> tt now } ruleCurrentDayofweek :: Rule ruleCurrentDayofweek = Rule { name = "current <day-of-week>" , pattern = [ Predicate isADayOfWeek , regex "(הזה|הזאת|הקרוב(ה)?)" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 True td _ -> Nothing } ruleFromDatetimeDatetimeInterval :: Rule ruleFromDatetimeDatetimeInterval = Rule { name = "from <datetime> - <datetime> (interval)" , pattern = [ regex "מ|משעה" , dimension Time , regex "\\-|עד" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Time td1:_:Token Time td2:_) -> Token Time <$> interval TTime.Closed td1 td2 _ -> Nothing } ruleNamedday4 :: Rule ruleNamedday4 = Rule { name = "named-day" , pattern = [ regex "(יום )?רביעי" ] , prod = \_ -> tt $ dayOfWeek 3 } ruleTheCycleAfterTime :: Rule ruleTheCycleAfterTime = Rule { name = "the <cycle> after <time>" , pattern = [ regex "ה" , dimension TimeGrain , regex "אחרי" , dimension Time ] , prod = \tokens -> case tokens of (_:Token TimeGrain grain:_:Token Time td:_) -> tt $ cycleNthAfter False grain 1 td _ -> Nothing } ruleTheCycleBeforeTime :: Rule ruleTheCycleBeforeTime = Rule { name = "the <cycle> before <time>" , pattern = [ regex "ה" , dimension TimeGrain , regex "לפני" , dimension Time ] , prod = \tokens -> case tokens of (_:Token TimeGrain grain:_:Token Time td:_) -> tt $ cycleNthAfter False grain (-1) td _ -> Nothing } ruleLastDayofweek :: Rule ruleLastDayofweek = Rule { name = "last <day-of-week>" , pattern = [ Predicate isADayOfWeek , regex "(שעבר(ה)?|הקודמת|הקודם)" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 True td _ -> Nothing } ruleTheIdesOfNamedmonth :: Rule ruleTheIdesOfNamedmonth = Rule { name = "the ides of <named-month>" , pattern = [ regex "באמצע" , Predicate isAMonth ] , prod = \tokens -> case tokens of (_:Token Time td@TimeData {TTime.form = Just (TTime.Month m)}:_) -> Token Time <$> intersect td (dayOfMonth $ if elem m [3, 5, 7, 10] then 15 else 13) _ -> Nothing } ruleNoon :: Rule ruleNoon = Rule { name = "noon" , pattern = [ regex "(ב)?צהריים" ] , prod = \_ -> tt $ hour False 12 } ruleToday :: Rule ruleToday = Rule { name = "today" , pattern = [ regex "היום" ] , prod = \_ -> tt today } ruleBetweenTimeofdayAndTimeofdayInterval :: Rule ruleBetweenTimeofdayAndTimeofdayInterval = Rule { name = "between <time-of-day> and <time-of-day> (interval)" , pattern = [ regex "בין" , Predicate isATimeOfDay , regex "ל" , Predicate isATimeOfDay ] , prod = \tokens -> case tokens of (_:Token Time td1:_:Token Time td2:_) -> Token Time <$> interval TTime.Closed td1 td2 _ -> Nothing } ruleNextCycle :: Rule ruleNextCycle = Rule { name = "next <cycle>" , pattern = [ dimension TimeGrain , regex "הבא(ה)?" ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_) -> tt $ cycleNth grain 1 _ -> Nothing } ruleForDuration :: Rule ruleForDuration = Rule { name = "for <duration>" , pattern = [ regex "תוך" , dimension Duration ] , prod = \tokens -> case tokens of (_:Token Duration dd:_) -> tt $ inDuration dd _ -> Nothing } ruleDurationFromNow :: Rule ruleDurationFromNow = Rule { name = "<duration> from now" , pattern = [ dimension Duration , regex "מעכשיו" ] , prod = \tokens -> case tokens of (Token Duration dd:_) -> tt $ inDuration dd _ -> Nothing } ruleLunch :: Rule ruleLunch = Rule { name = "lunch" , pattern = [ regex "(ב)?צהריים" ] , 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 "האחרון|האחרונה|שעבר|שעברה" ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_) -> tt . cycleNth grain $ - 1 _ -> Nothing } ruleAfternoon :: Rule ruleAfternoon = Rule { name = "afternoon" , pattern = [ regex "אחה(״)?צ|אחר הצהריים" ] , prod = \_ -> Token Time . partOfDay . mkLatent <$> interval TTime.Open (hour False 12) (hour False 19) } ruleNamedmonthDayofmonthOrdinal :: Rule ruleNamedmonthDayofmonthOrdinal = Rule { name = "<named-month> <day-of-month> (ordinal)" , pattern = [ Predicate isAMonth , Predicate isDOMOrdinal ] , prod = \tokens -> case tokens of (Token Time td:token:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleNamedday5 :: Rule ruleNamedday5 = Rule { name = "named-day" , pattern = [ regex "(יום )?חמישי" ] , prod = \_ -> tt $ dayOfWeek 4 } ruleDayofmonthordinalNamedmonth :: Rule ruleDayofmonthordinalNamedmonth = Rule { name = "<day-of-month>(ordinal) <named-month>" , pattern = [ Predicate isDOMOrdinal , Predicate isAMonth ] , prod = \tokens -> case tokens of (token:Token Time td:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleIntersectBy :: Rule ruleIntersectBy = Rule { name = "intersect by \",\"" , pattern = [ Predicate isNotLatent , regex "," , Predicate isNotLatent ] , prod = \tokens -> case tokens of (Token Time td1:_:Token Time td2:_) -> Token Time <$> intersect td1 td2 _ -> Nothing } ruleNthTimeAfterTime :: Rule ruleNthTimeAfterTime = Rule { name = "nth <time> after <time>" , pattern = [ dimension Ordinal , dimension Time , regex "אחרי" , dimension Time ] , prod = \tokens -> case tokens of (Token Ordinal od:Token Time td1:_:Token Time td2:_) -> tt $ predNthAfter (TOrdinal.value od - 1) td1 td2 _ -> Nothing } ruleMmdd :: Rule ruleMmdd = Rule { name = "mm/dd" , pattern = [ regex "(0?[1-9]|1[0-2])/(3[01]|[12]\\d|0?[1-9])" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (mm:dd:_)):_) -> do m <- parseInt mm d <- parseInt dd tt $ monthDay m d _ -> Nothing } ruleAfterDuration :: Rule ruleAfterDuration = Rule { name = "after <duration>" , pattern = [ regex "אחרי" , dimension Duration ] , prod = \tokens -> case tokens of (_:Token Duration dd:_) -> tt . withDirection TTime.After $ inDuration dd _ -> 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 } ruleDayofmonthOrdinalOfNamedmonth :: Rule ruleDayofmonthOrdinalOfNamedmonth = Rule { name = "<day-of-month> (ordinal) of <named-month>" , pattern = [ Predicate isDOMOrdinal , regex "של|ב|ל" , Predicate isAMonth ] , prod = \tokens -> case tokens of (token:_:Token Time td:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleThisEvening :: Rule ruleThisEvening = Rule { name = "this evening" , pattern = [ regex "הערב" ] , prod = \_ -> do td <- interval TTime.Open (hour False 18) (hour False 0) Token Time . partOfDay <$> intersect today td } ruleBetweenDatetimeAndDatetimeInterval :: Rule ruleBetweenDatetimeAndDatetimeInterval = Rule { name = "between <datetime> and <datetime> (interval)" , pattern = [ regex "בין" , dimension Time , regex "ל" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Time td1:_:Token Time td2:_) -> Token Time <$> interval TTime.Closed td1 td2 _ -> Nothing } ruleEndOfYear :: Rule ruleEndOfYear = Rule { name = "End of year" , pattern = [ regex "סוף (ה)?שנה" ] , prod = \_ -> tt $ cycleNth TG.Year 1 } ruleDurationAgo :: Rule ruleDurationAgo = Rule { name = "<duration> ago" , pattern = [ regex "לפני" , dimension Duration ] , prod = \tokens -> case tokens of (_:Token Duration dd:_) -> tt $ durationAgo dd _ -> Nothing } ruleLastNCycle :: Rule ruleLastNCycle = Rule { name = "last n <cycle>" , pattern = [ Predicate $ isIntegerBetween 1 9999 , dimension TimeGrain , regex "אחרון|אחרונות|אחרונה|אחרונים" ] , prod = \tokens -> case tokens of (token:Token TimeGrain grain:_) -> do v <- getIntValue token tt . cycleN True grain $ - v _ -> Nothing } ruleMidnighteodendOfDay :: Rule ruleMidnighteodendOfDay = Rule { name = "midnight|EOD|end of day" , pattern = [ regex "(ב)?חצות" ] , prod = \_ -> tt $ hour False 0 } ruleDayofmonthNonOrdinalNamedmonth :: Rule ruleDayofmonthNonOrdinalNamedmonth = Rule { name = "<day-of-month> (non ordinal) <named-month>" , pattern = [ Predicate isDOMInteger , Predicate isAMonth ] , prod = \tokens -> case tokens of (token:Token Time td:_) -> Token Time <$> intersectDOM td token _ -> 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 } ruleUntilTimeofday :: Rule ruleUntilTimeofday = Rule { name = "until <time-of-day>" , pattern = [ regex "עד" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ withDirection TTime.Before td _ -> Nothing } ruleAtTimeofday :: Rule ruleAtTimeofday = Rule { name = "at <time-of-day>" , pattern = [ regex "ב" , Predicate isATimeOfDay ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleNthTimeOfTime :: Rule ruleNthTimeOfTime = Rule { name = "nth <time> of <time>" , pattern = [ dimension Time , dimension Ordinal , regex "של|ב" , dimension Time ] , prod = \tokens -> case tokens of (Token Time td1:Token Ordinal od:_:Token Time td2:_) -> Token Time . predNth (TOrdinal.value od - 1) False <$> intersect td2 td1 _ -> Nothing } ruleTimePartofday :: Rule ruleTimePartofday = Rule { name = "<time> <part-of-day>" , pattern = [ dimension Time , Predicate isAPartOfDay ] , prod = \tokens -> case tokens of (Token Time td:Token Time pod:_) -> Token Time <$> intersect pod td _ -> Nothing } ruleWeekend :: Rule ruleWeekend = Rule { name = "week-end" , pattern = [ regex "(סופ״ש|סוף השבוע)" ] , prod = \_ -> tt weekend } ruleNameddayDayofmonthOrdinal :: Rule ruleNameddayDayofmonthOrdinal = Rule { name = "<named-day> <day-of-month> (ordinal)" , pattern = [ Predicate isADayOfWeek , Predicate isDOMOrdinal ] , prod = \tokens -> case tokens of (Token Time td:token:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleDate :: Rule ruleDate = Rule { name = "ב <date>" , pattern = [ regex "ב" , dimension Time ] , prod = \tokens -> case tokens of (_:x:_) -> Just x _ -> Nothing } ruleNextTime :: Rule ruleNextTime = Rule { name = "next <time>" , pattern = [ Predicate isNotLatent , regex "הבא(ה)?" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 True td _ -> Nothing } ruleOrdinalQuarterYear :: Rule ruleOrdinalQuarterYear = Rule { name = "<ordinal> quarter <year>" , pattern = [ dimension Ordinal , Predicate $ isGrain TG.Quarter , dimension Time ] , prod = \tokens -> case tokens of (Token Ordinal od:_:Token Time td:_) -> tt $ cycleNthAfter False TG.Quarter (TOrdinal.value od - 1) td _ -> Nothing } 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 } ruleTheOrdinalCycleAfterTime :: Rule ruleTheOrdinalCycleAfterTime = Rule { name = "the <ordinal> <cycle> after <time>" , pattern = [ regex "ה" , dimension Ordinal , dimension TimeGrain , regex "אחרי|לאחר" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) -> tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td _ -> Nothing } ruleNextNCycle :: Rule ruleNextNCycle = Rule { name = "next n <cycle>" , pattern = [ Predicate $ isIntegerBetween 1 9999 , dimension TimeGrain , regex "הבא|הבאה|הבאים|הבאות" ] , 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 "(ב)?בוקר" ] , 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 "הקרו(ב)?ה|הזה|הזאת" ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_) -> tt $ cycleNth grain 0 _ -> Nothing } ruleThisTime :: Rule ruleThisTime = Rule { name = "this <time>" , pattern = [ dimension Time , regex "הקרוב|הזה" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ predNth 0 False td _ -> Nothing } ruleDayofmonthNonOrdinalOfNamedmonth :: Rule ruleDayofmonthNonOrdinalOfNamedmonth = Rule { name = "<day-of-month> (non ordinal) of <named-month>" , pattern = [ Predicate isDOMInteger , regex "של|ב|ל" , Predicate isAMonth ] , prod = \tokens -> case tokens of (token:_:Token Time td:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleEndOfMonth :: Rule ruleEndOfMonth = Rule { name = "End of month" , pattern = [ regex "סוף (ה)?חודש" ] , prod = \_ -> tt $ cycleNth TG.Month 1 } ruleYesterday :: Rule ruleYesterday = Rule { name = "yesterday" , pattern = [ regex "(אתמול|אמש)" ] , prod = \_ -> tt . cycleNth TG.Day $ - 1 } ruleAfterTimeofday :: Rule ruleAfterTimeofday = Rule { name = "after <time-of-day>" , pattern = [ regex "אחרי" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Time td:_) -> tt $ withDirection TTime.After td _ -> Nothing } ruleDayofmonthOrdinal :: Rule ruleDayofmonthOrdinal = Rule { name = "<day-of-month> (ordinal)" , pattern = [ Predicate isDOMOrdinal ] , prod = \tokens -> case tokens of (token:_) -> do n <- getIntValue token tt . mkLatent $ dayOfMonth n _ -> 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 (Text.toLower ap == "a") td _ -> Nothing } ruleOrdinalCycleAfterTime :: Rule ruleOrdinalCycleAfterTime = Rule { name = "<ordinal> <cycle> after <time>" , pattern = [ dimension Ordinal , dimension TimeGrain , regex "אחרי|לאחר" , dimension Time ] , prod = \tokens -> case tokens of (Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) -> tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td _ -> Nothing } ruleNamedday7 :: Rule ruleNamedday7 = Rule { name = "named-day" , pattern = [ regex "(יום )?שבת" ] , prod = \_ -> tt $ dayOfWeek 6 } ruleHhmm :: Rule ruleHhmm = Rule { name = "hh:mm" , pattern = [ regex "((?:[01]?\\d)|(?:2[0-3]))[:.]([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 } ruleTimeOfPartofday :: Rule ruleTimeOfPartofday = Rule { name = "<time> of <part-of-day>" , pattern = [ dimension Time , regex "ב" , Predicate isAPartOfDay ] , prod = \tokens -> case tokens of (Token Time td1:_:Token Time td2:_) -> Token Time <$> intersect td1 td2 _ -> Nothing } ruleYear :: Rule ruleYear = Rule { name = "year" , pattern = [ Predicate $ isIntegerBetween 1000 2100 ] , prod = \tokens -> case tokens of (token:_) -> do n <- getIntValue token tt $ year n _ -> Nothing } ruleNamedmonthDayofmonthNonOrdinal :: Rule ruleNamedmonthDayofmonthNonOrdinal = Rule { name = "<named-month> <day-of-month> (non ordinal)" , pattern = [ Predicate isAMonth , Predicate isDOMInteger ] , prod = \tokens -> case tokens of (Token Time td:token:_) -> Token Time <$> intersectDOM td token _ -> Nothing } ruleNamedday8 :: Rule ruleNamedday8 = Rule { name = "named-day" , pattern = [ regex "(יום )?ראשון" ] , prod = \_ -> tt $ dayOfWeek 7 } ruleAbsorptionOfAfterNamedDay :: Rule ruleAbsorptionOfAfterNamedDay = Rule { name = "absorption of , after named day" , pattern = [ Predicate isADayOfWeek , regex "," ] , prod = \tokens -> case tokens of (x:_) -> Just x _ -> Nothing } ruleLastDayofweekOfTime :: Rule ruleLastDayofweekOfTime = Rule { name = "last <day-of-week> of <time>" , pattern = [ Predicate isADayOfWeek , regex "האחרון של" , dimension Time ] , prod = \tokens -> case tokens of (Token Time td1:_:Token Time td2:_) -> tt $ predLastOf td1 td2 _ -> 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 (Text.toLower ap == "a") $ hourMinute True h m _ -> Nothing } ruleCycleBeforeTime :: Rule ruleCycleBeforeTime = Rule { name = "<cycle> before <time>" , pattern = [ dimension TimeGrain , regex "לפני" , dimension Time ] , prod = \tokens -> case tokens of (Token TimeGrain grain:_:Token Time td:_) -> tt $ cycleNthAfter False grain (-1) td _ -> Nothing } ruleDurationAfterTime :: Rule ruleDurationAfterTime = Rule { name = "<duration> after <time>" , pattern = [ dimension Duration , regex "אחרי|לאחר" , dimension Time ] , prod = \tokens -> case tokens of (Token Duration dd:_:Token Time td:_) -> tt $ durationAfter dd td _ -> Nothing } ruleEveningnight :: Rule ruleEveningnight = Rule { name = "evening|night" , pattern = [ regex "(ב)?ערב" ] , prod = \_ -> Token Time . partOfDay . mkLatent <$> interval TTime.Open (hour False 18) (hour False 0) } ruleOrdinalQuarter :: Rule ruleOrdinalQuarter = Rule { name = "<ordinal> quarter" , pattern = [ dimension Ordinal , Predicate $ isGrain TG.Quarter ] , prod = \tokens -> case tokens of (token:_) -> do n <- getIntValue token tt . cycleNthAfter True TG.Quarter (n - 1) $ cycleNth TG.Year 0 _ -> Nothing } ruleNamedday3 :: Rule ruleNamedday3 = Rule { name = "named-day" , pattern = [ regex "(יום )?שלישי" ] , prod = \_ -> tt $ dayOfWeek 2 } ruleTheDayofmonthOrdinal :: Rule ruleTheDayofmonthOrdinal = Rule { name = "the <day-of-month> (ordinal)" , pattern = [ regex "ה" , Predicate isDOMOrdinal ] , prod = \tokens -> case tokens of (_: Token Ordinal OrdinalData{TOrdinal.value = v}: _) -> tt $ dayOfMonth v _ -> Nothing } ruleDurationBeforeTime :: Rule ruleDurationBeforeTime = Rule { name = "<duration> before <time>" , pattern = [ dimension Duration , regex "לפני" , dimension Time ] , prod = \tokens -> case tokens of (Token Duration dd:_:Token Time td:_) -> tt $ durationBefore dd td _ -> Nothing } rulePartofdayOfTime :: Rule rulePartofdayOfTime = Rule { name = "<part-of-day> of <time>" , pattern = [ regex "ב" , Predicate isAPartOfDay , regex "של" , dimension Time ] , prod = \tokens -> case tokens of (_:Token Time td1:_:Token Time td2:_) -> Token Time <$> intersect td1 td2 _ -> Nothing } ruleMmddyyyy :: Rule ruleMmddyyyy = Rule { name = "mm/dd/yyyy" , pattern = [ regex "(0?[1-9]|1[0-2])[/-](3[01]|[12]\\d|0?[1-9])[-/](\\d{2,4})" ] , prod = \tokens -> case tokens of (Token RegexMatch (GroupMatch (mm:dd:yy:_)):_) -> do y <- parseInt yy m <- parseInt mm d <- parseInt dd tt $ yearMonthDay y m d _ -> Nothing } ruleTomorrow :: Rule ruleTomorrow = Rule { name = "tomorrow" , pattern = [ regex "(מחר|למחרת)" ] , prod = \_ -> tt $ cycleNth TG.Day 1 } ruleTimeofdayOclock :: Rule ruleTimeofdayOclock = Rule { name = "<time-of-day> o'clock" , pattern = [ Predicate isATimeOfDay , regex "o.?clock" ] , prod = \tokens -> case tokens of (Token Time td:_) -> tt $ notLatent td _ -> Nothing } ruleDayofmonthordinalNamedmonthYear :: Rule ruleDayofmonthordinalNamedmonthYear = Rule { name = "<day-of-month>(ordinal) <named-month> year" , pattern = [ Predicate isDOMOrdinal , Predicate isAMonth , regex "(\\d{2,4})" ] , prod = \tokens -> case tokens of (token:Token Time td:Token RegexMatch (GroupMatch (match:_)):_) -> do intVal <- parseInt match dom <- intersectDOM td token Token Time <$> intersect dom (year intVal) _ -> Nothing } 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 } ruleMonths :: [Rule] ruleMonths = mkRuleMonths [ ( "ינואר", "ינואר" ) , ( "פברואר", "פברואר" ) , ( "מרץ", "מרץ" ) , ( "אפריל", "אפריל" ) , ( "מאי", "מאי" ) , ( "יוני", "יוני" ) , ( "יולי", "יולי" ) , ( "אוגוסט", "אוגוסט" ) , ( "ספטמבר", "ספטמבר" ) , ( "אוקטובר", "אוקטובר" ) , ( "נובמבר", "נובמבר" ) , ( "דצמבר", "דצמבר" ) ] rules :: [Rule] rules = [ ruleAbsorptionOfAfterNamedDay , ruleAfterDuration , ruleAfterTimeofday , ruleAfternoon , ruleAtHourTimeofday , ruleAtTimeofday , ruleBetweenDatetimeAndDatetimeInterval , ruleBetweenTimeofdayAndTimeofdayInterval , ruleCurrentDayofweek , ruleCycleAfterTime , ruleCycleBeforeTime , ruleDate , ruleDatetimeDatetimeInterval , ruleDayofmonthNonOrdinalNamedmonth , ruleDayofmonthNonOrdinalOfNamedmonth , ruleDayofmonthOrdinal , ruleDayofmonthOrdinalOfNamedmonth , ruleDayofmonthordinalNamedmonth , ruleDayofmonthordinalNamedmonthYear , ruleDurationAfterTime , ruleDurationAgo , ruleDurationBeforeTime , ruleDurationFromNow , ruleEndOfMonth , ruleEndOfYear , ruleEveningnight , ruleForDuration , ruleFromDatetimeDatetimeInterval , ruleHhmm , ruleHhmmMilitaryAmpm , ruleHhmmss , ruleHourofdayAndInteger , ruleHourofdayAndQuarter , ruleHourofdayAndHalf , ruleHourofdayInteger , ruleHourofdayQuarter , ruleHourofdayHalf , ruleInDuration , ruleInNamedmonth , ruleIntersect , ruleIntersectBy , ruleLastCycle , ruleLastDayofweek , ruleLastDayofweekOfTime , ruleLastNCycle , ruleLastTime , ruleLunch , ruleMidnighteodendOfDay , ruleMmdd , ruleMmddyyyy , ruleMorning , ruleNamedday , ruleNamedday2 , ruleNamedday3 , ruleNamedday4 , ruleNamedday5 , ruleNamedday6 , ruleNamedday7 , ruleNamedday8 , ruleNameddayDayofmonthOrdinal , ruleNamedmonthDayofmonthNonOrdinal , ruleNamedmonthDayofmonthOrdinal , ruleNextCycle , ruleNextDayofweek , ruleNextNCycle , ruleNextTime , ruleNoon , ruleNow , ruleNthTimeAfterTime , ruleNthTimeOfTime , ruleOrdinalCycleAfterTime , ruleOrdinalQuarter , ruleOrdinalQuarterYear , rulePartofdayOfTime , ruleIntegerAfterpastIntegerHourofday , ruleQuarterAfterpastIntegerHourofday , ruleHalfAfterpastIntegerHourofday , ruleIntegerTotillbeforeIntegerHourofday , ruleQuarterTotillbeforeIntegerHourofday , ruleHalfTotillbeforeIntegerHourofday , ruleSinceTimeofday , ruleTheCycleAfterTime , ruleTheCycleBeforeTime , ruleTheDayofmonthNonOrdinal , ruleTheDayofmonthOrdinal , ruleTheIdesOfNamedmonth , ruleTheOrdinalCycleAfterTime , ruleThisCycle , ruleThisEvening , ruleThisTime , ruleTimeOfPartofday , ruleTimePartofday , ruleTimeofdayAmpm , ruleTimeofdayLatent , ruleTimeofdayOclock , ruleToday , ruleTomorrow , ruleUntilTimeofday , ruleWeekend , ruleYear , ruleYesterday , ruleYyyymmdd ] ++ ruleMonths