/
plural_rules_compiler.rb
93 lines (75 loc) · 2.79 KB
/
plural_rules_compiler.rb
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
86
87
88
89
90
91
92
93
# encoding: UTF-8
# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0
require 'ruby_parser'
module TwitterCldr
module Js
module Renderers
module PluralRules
class PluralRulesCompiler
class << self
def rule_to_js(rule_code)
tree = RubyParser.new.parse(rule_code).to_a
"function(n) { return #{statement_list(tree)} }"
end
protected
def statement_list(tree)
if tree.first == :block
tree[1..-1].map { |sub_tree| send(:"_#{sub_tree.first}", sub_tree) }.join(" ")
else
send(:"_#{tree.first}", tree)
end
end
def _if(tree)
result = "(function() { if (#{statement_list(tree[1])}) { return #{statement_list(tree[2])} }"
result << " else { return #{statement_list(tree[3])} }" if tree[3]
"#{result} })();"
end
def _lvar(tree)
tree.first.to_s
end
def _call(tree)
case tree[2]
when :==, :%, :<, :> # special operators that actually resolve to method calls
"#{statement_list(tree[1])} #{tree[2]} #{statement_list(tree[3])}"
when :include?
"#{statement_list(tree[1])}.indexOf(#{statement_list(tree[3])}) >= 0"
when :between?
smt = "((#{statement_list(tree[1])} >= #{statement_list(tree[3][1])})"
smt << " && (#{statement_list(tree[1])} <= #{statement_list(tree[3][2])}))"
smt
else
# this should be the only case where tree[1] might be nil (i.e. the method was not called on any object)
call = tree[1] ? "#{statement_list(tree[1])}.#{tree[2]}" : tree[2].to_s
arglist = statement_list(tree[3])
arglist == "" ? call : "#{call}(#{arglist})"
end
end
def _arglist(tree)
tree[1..-1].map { |arg| statement_list(arg) }.join(", ")
end
def _lit(tree)
if tree[1].is_a?(Symbol) || tree[1].is_a?(String)
%Q("#{tree[1]}")
else
tree[1]
end
end
def _array(tree)
"[#{tree[1..-1].map { |arg| statement_list(arg) }.join(", ")}]"
end
def _not(tree)
"!(#{statement_list(tree[1])})"
end
def _and(tree)
"#{statement_list(tree[1])} && #{statement_list(tree[2])}"
end
def _or(tree)
"#{statement_list(tree[1])} || #{statement_list(tree[2])}"
end
end
end
end
end
end
end