summaryrefslogtreecommitdiff
path: root/lib/date/delta/parser.ry
blob: 4de8aa1e46e88e0156e4bdd83947b77a7b84780c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# parser.ry: Written by Tadayoshi Funaba 2006,2008-2010 -*- ruby -*-

class Date::Delta::Parser

  prechigh
    nonassoc UNARY
    left '^'
    left '*' '/'
    left '+' ',' AND '-'
  preclow

  rule

  stmt	: expr
	;

  expr	: time
	| iso
	| expr '+' expr   {result += val[2]}
	| expr ',' expr   {result += val[2]}
	| expr AND expr   {result += val[2]}
	| expr '-' expr   {result -= val[2]}
	| expr '*' DIGITS {result *= val[2]}
	| expr '/' DIGITS {result /= val[2]}
	| expr '^' DIGITS {result **= val[2]}
	| '-' expr =UNARY {result = -val[1]}
	| '+' expr =UNARY {result = +val[1]}
	| '(' expr ')'    {result =  val[1]}
	;

  time	: DIGITS unit {result = val[0] * val[1]}
	;

  unit	: {result = 1} | UNIT
	;

  iso	: DURATION
	;

---- header ----
---- inner ----

  def lookup(str)
    t = str.downcase
    k = UNITS4KEY[t]
    return [:UNIT, k] if k
    return [:AND, nil] if t == 'and'
    return [:UNKNOWNWORD, nil]
  end

  def parse(str)
    @q = []
    until str.empty?
      case str
      when /\A\s+/
      when /\Ap\d+[ymdhsw]/i
	/\Ap(\d+y)?(\d+m)?(\d+d)?t?(\d+h)?(\d+m)?(\d+s)?(\d+w)?/i =~ str
	y, m, d, h, min, s, w =
	  [$1, $2, $3, $4, $5, $6, $7].collect{|x| x.to_i}
	y *= UNITS4KEY['years']
	m *= UNITS4KEY['months']
	d *= UNITS4KEY['days']
	h *= UNITS4KEY['hours']
	min *= UNITS4KEY['minutes']
	s *= UNITS4KEY['seconds']
	w *= UNITS4KEY['weeks']
	@q.push [:DURATION, y + m + d + h + min + s + w]
      when /\A\d+/
	@q.push [:DIGITS, $&.to_i]
      when /\A[a-z]+/i
	@q.push lookup($&)
      when /\A.|\n/
	@q.push [$&, $&]
      end
      str = $'
    end
    @q.push [false, false]
    do_parse
  end

  def next_token
    @q.shift
  end

---- footer ----