some Ruby stuff, just my little toys
[xorg/xkeyboard-config] / tests / ruby / xkbparser.rb
1 #
2 # $Id$
3 #
4 # Commont parsing classes for symbols/inet
5 # The parsing is simplified, based on regex - it is NOT a real parser for very
6 # complex XKB format
7 #
8
9 class Symbols < Hash
10
11   #
12   # Constructor
13   #
14   def initialize
15     @includedSyms = Array.new
16   end
17
18   # Write-only property, parent list of symbols definitions
19   def symbols_list=(symbolsList)
20     @symbolsList = symbolsList
21   end
22
23   # Whether this set of symbols is hidden or not
24   def hidden?
25     @hidden
26   end
27
28   def hidden=(h)
29     @hidden = h
30   end
31
32   #
33   # Add "dependency" - the symbols referenced using the "include" statement.
34   #
35   def add_included(other)
36     @includedSyms.push(other)
37   end
38
39   alias get_original []
40
41   #
42   # Get the symbol, trying first own definitions, then walking through all 
43   # dependenies
44   #
45   def [](symName)
46     own = self.get_original(symName)
47     if own.nil?
48       @includedSyms.find_all do | symsName |
49         syms = @symbolsList[symsName]
50         his = syms[symName]
51         if !his.nil?
52           own = his
53           break
54         end
55       end
56     end
57     own
58   end
59
60   #
61   # Create a hash including all elements of this hash which are not in the
62   # other hash, use symbols + and * for marking the elements which existed in
63   # the original hash (+ if not existed)
64   #
65   def -(other)
66     diff = self.class.new
67     self.find_all do | key, value | 
68       existing = other[key]
69       if existing != value
70         diff[key] = [ value, existing.nil? ? '+' : '' ]
71       end 
72     end
73     diff
74   end
75
76
77   def to_s
78     s = "{\n"
79     # First output included syms
80     @includedSyms.find_all do | symsName |
81        s += "  include \"inet(#{symsName})\"\n"
82     end
83     # Then - own definitions
84     self.find_all do | key, value |
85        s += "  key #{key} { [ #{value} ] };\n"
86     end
87     s + "}";
88   end
89
90 end
91
92 class SymbolsList < Hash
93
94   #
95   # Add new xkb_symbols
96   #
97   def add_symbols (symbolsName, hidden)
98     newSyms = Symbols.new
99     newSyms.symbols_list = self
100     newSyms.hidden = hidden
101     self[symbolsName] = newSyms
102   end
103
104   def to_s
105     s = "// Autogenerated\n\n"
106     self.find_all do | symbols, mapping |
107       s += "partial alphanumeric_keys\nxkb_symbols \"#{symbols}\" #{mapping};\n\n" 
108     end
109     s
110   end
111
112   def match_symbols(new_symbols,limit)
113     matching = Hash.new
114     find_all do | symbols, mapping |
115       diff = new_symbols - mapping
116       if diff.size <= limit
117         matching[symbols] = diff
118       end
119     end
120     matching
121   end
122
123 end
124
125 class Parser
126
127   def parse (fileName)
128     allSyms = SymbolsList.new;
129     currentSyms = nil
130     hidden = false
131     File.open(fileName) do | file |
132       file.each_line do | line |
133         line.scan(/xkb_symbols\s+"(\w+)"/) do | symsName |
134           currentSyms = allSyms.add_symbols(symsName[0], hidden)
135         end
136         line.scan(/^\s*key\s*<(\w+)>\s*\{\s*\[\s*(\w+)/) do | keycode, keysym |
137           currentSyms[keycode] = keysym
138         end
139         line.scan(/^partial\s+(hidden\s+)?alphanumeric_keys/) do | h |
140           hidden = !h[0].nil?
141         end
142         line.scan(/^\s*include\s+"inet\((\w+)\)"/) do | otherPart |
143           currentSyms.add_included(otherPart[0])
144         end
145       end
146     end
147     allSyms
148   end
149
150 end