2 # vi: set softtabstop=4 shiftwidth=4 tabstop=8 expandtab:
4 """Splits a command into source, destination, and time."""
11 import LandmarkMatcher
19 class CommandParseException(Exception):
23 def __init__(self
, str):
25 self
.landmarkMatcher
= None
30 # Look for start and end at the start of the string.
31 match
= _full_rx
.match(str)
33 raise CommandParseException("Failed to extract source and "
34 "destination from command '%s'" % str);
36 self
.cmd
.start
= self
.parseLocation(match
.group("start"))
37 self
.cmd
.end
= self
.parseLocation(match
.group("end"))
39 # Now look for time constraints.
40 rule
= match
.group("rule")
41 timestr
= match
.group("time")
44 "by": PlanTime
.MUST_ARRIVE_BEFORE
,
45 "at": PlanTime
.MUST_LEAVE_AFTER
,
48 = PlanTime
.PlanTime(self
.decodeTime(timestr
), ruleMap
[rule
])
50 def parseLocation(self
, str):
51 match
= _intersection_rx
.match(str)
53 return PlanLocation
.IntersectionLocation(match
.group(1),
56 match
= _stop_rx
.match(str)
58 return PlanLocation
.StopLocation(match
.group(1))
60 match
= _address_rx
.match(str)
62 return PlanLocation
.AddressLocation(str)
65 if self
.landmarkMatcher
is None:
66 self
.landmarkMatcher
= LandmarkMatcher
.LandmarkMatcher()
67 return PlanLocation
.LandmarkLocation(self
.landmarkMatcher
.match(str))
69 def decodeTime(self
, str):
70 match
= _time_rx
.match(str)
72 raise CommandParseException("Unable to decode timespec '%s'" % str)
74 hour
= int(match
.group("hour"))
77 minstr
= match
.group("min")
78 if minstr
is not None:
81 mod
= match
.group("mod")
83 if hour
< 0 or hour
> 23 or min < 0 or min > 59:
84 raise CommandParseException("Invalid numbers in time '%s'" % str)
86 if mod
is not None and hour
< 12 and mod
.lower() == "pm":
89 t
= list(time
.localtime())
94 _full_re
= ("(?i)^\s*(?P<start>.*?)\s+to\s+(?P<end>.*?)\s*"
95 # at this point the pattern either ends, or there's a timespec
96 # Require the time to have at least one digit so people can still
97 # use "at" for intersections (although "and" is better)
98 "(?:$|(?P<rule>by|at)\s+(?P<time>\d.*?)\s*$)")
99 _full_rx
= re
.compile(_full_re
)
101 _intersection_re
= "(?i)^(.+?)\s+(?:at|and)\s*(.+?)$"
102 _intersection_rx
= re
.compile(_intersection_re
)
104 # "stop 6037" or just "6037"
105 _stop_re
= "(?i)^(?:stop)?\s*(\d{4})$"
106 _stop_rx
= re
.compile(_stop_re
)
109 _address_re
= '(?i)^\d+\s+\S.*'
110 _address_rx
= re
.compile(_address_re
)
117 _time_re
= ("^(?P<hour>\d{1,2}):?(?P<min>\d\d)?\s*(?i)(?P<mod>am?|pm?)?$")
118 _time_rx
= re
.compile(_time_re
)