rgviz 0.2 → 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,403 @@
1
+ module Rgviz
2
+ class Parser < Lexer
3
+ def initialize(string)
4
+ super
5
+ @query = Query.new
6
+ next_token
7
+ end
8
+
9
+ def parse
10
+ parse_select
11
+ parse_where
12
+ parse_group_by
13
+ parse_pivot
14
+ parse_order_by
15
+ parse_limit
16
+ parse_offset
17
+ parse_label
18
+ parse_format
19
+ parse_options
20
+
21
+ check Token::EOF
22
+ @query
23
+ end
24
+
25
+ def parse_select
26
+ return if not token_is! Token::Select
27
+
28
+ @query.select = Select.new
29
+
30
+ return if token_is! Token::STAR
31
+
32
+ parse_columns @query.select.columns
33
+
34
+ raise ParseException.new "Expecting select columns" if @query.select.columns.empty?
35
+ end
36
+
37
+ def parse_where
38
+ return if not token_is! Token::Where
39
+
40
+ @query.where = Where.new parse_expression
41
+ end
42
+
43
+ def parse_group_by
44
+ return if not token_is! Token::Group
45
+ check! Token::By
46
+
47
+ @query.group_by = GroupBy.new
48
+ @query.group_by.columns = parse_columns
49
+
50
+ raise ParseException.new "Expecting group by columns" if @query.group_by.columns.empty?
51
+ end
52
+
53
+ def parse_pivot
54
+ return if not token_is! Token::Pivot
55
+
56
+ @query.pivot = Pivot.new
57
+ @query.pivot.columns = parse_columns
58
+
59
+ raise ParseException.new "Expecting pivot columns" if @query.pivot.columns.empty?
60
+ end
61
+
62
+ def parse_order_by
63
+ return if not token_is! Token::Order
64
+ check! Token::By
65
+
66
+ @query.order_by = OrderBy.new
67
+ @query.order_by.sorts = parse_sorts
68
+
69
+ raise ParseException.new "Expecting order by columns" if @query.order_by.sorts.empty?
70
+ end
71
+
72
+ def parse_limit
73
+ return if not token_is! Token::Limit
74
+
75
+ check Token::INTEGER
76
+
77
+ @query.limit = @token.number
78
+ next_token
79
+ end
80
+
81
+ def parse_offset
82
+ return if not token_is! Token::Offset
83
+
84
+ check Token::INTEGER
85
+
86
+ @query.offset = @token.number
87
+ next_token
88
+ end
89
+
90
+ def parse_label
91
+ return if not token_is! Token::Label
92
+
93
+ @query.labels = []
94
+
95
+ column = parse_column
96
+ raise ParseException.new "Expecting label" unless column
97
+
98
+ check Token::STRING
99
+ @query.labels << Label.new(column, @token.string)
100
+ next_token
101
+
102
+ while token_is! Token::COMMA
103
+ column = parse_column
104
+ break unless column
105
+
106
+ check Token::STRING
107
+ @query.labels << Label.new(column, @token.string)
108
+ next_token
109
+ end
110
+
111
+ raise ParseException.new "Expecting label" if @query.labels.empty?
112
+ end
113
+
114
+ def parse_format
115
+ return if not token_is! Token::Format
116
+
117
+ @query.formats = []
118
+
119
+ column = parse_column
120
+ raise ParseException.new "Expecting format" unless column
121
+
122
+ check Token::STRING
123
+ @query.formats << Format.new(column, @token.string)
124
+ next_token
125
+
126
+ while token_is! Token::COMMA
127
+ column = parse_column
128
+ break unless column
129
+
130
+ check Token::STRING
131
+ @query.formats << Format.new(column, @token.string)
132
+ next_token
133
+ end
134
+
135
+ raise ParseException.new "Expecting format" if @query.formats.empty?
136
+ end
137
+
138
+ def parse_options
139
+ return if not token_is! Token::Options
140
+
141
+ @query.options = []
142
+
143
+ while @token.value == Token::NoValues || @token.value == Token::NoFormat
144
+ @query.options << Option.new(@token.value)
145
+ next_token
146
+ end
147
+
148
+ raise ParseException.new "Expecting option" if @query.options.empty?
149
+ raise ParseException.new "Unknown option" if @token.value != Token::EOF
150
+ end
151
+
152
+ def parse_sorts
153
+ sorts = []
154
+
155
+ column = parse_column
156
+ return sorts unless column
157
+
158
+ order = parse_sort_order
159
+
160
+ sorts << Sort.new(column, order)
161
+ while token_is! Token::COMMA
162
+ column = parse_column
163
+ break unless column
164
+
165
+ order = parse_sort_order
166
+ sorts << Sort.new(column, order)
167
+ end
168
+ sorts
169
+ end
170
+
171
+ def parse_sort_order
172
+ if token_is! Token::Asc
173
+ Sort::Asc
174
+ elsif token_is! Token::Desc
175
+ Sort::Desc
176
+ else
177
+ Sort::Asc
178
+ end
179
+ end
180
+
181
+ def parse_expression
182
+ parse_or_expression
183
+ end
184
+
185
+ def parse_or_expression
186
+ left = parse_and_expression
187
+ if token_is! Token::Or
188
+ right = parse_and_expression
189
+ BinaryExpression.new left, BinaryExpression::Or, right
190
+ else
191
+ left
192
+ end
193
+ end
194
+
195
+ def parse_and_expression
196
+ left = parse_not_expression
197
+ if token_is! Token::And
198
+ right = parse_not_expression
199
+ BinaryExpression.new left, BinaryExpression::And, right
200
+ else
201
+ left
202
+ end
203
+ end
204
+
205
+ def parse_not_expression
206
+ if token_is! Token::Not
207
+ operand = parse_primary_expression
208
+ UnaryExpression.new UnaryExpression::Not, operand
209
+ else
210
+ parse_primary_expression
211
+ end
212
+ end
213
+
214
+ def parse_primary_expression
215
+ case @token.value
216
+ when Token::LPAREN
217
+ next_token
218
+ exp = parse_expression
219
+ check! Token::RPAREN
220
+ return exp
221
+ else
222
+ left = parse_column
223
+ raise ParseException.new "Expecting left exp" unless left
224
+
225
+ case @token.value
226
+ when Token::Is
227
+ next_token
228
+ if token_is! Token::Not
229
+ check! Token::Null
230
+ return UnaryExpression.new UnaryExpression::IsNotNull, left
231
+ elsif token_is! Token::Null
232
+ return UnaryExpression.new UnaryExpression::IsNull, left
233
+ end
234
+ when Token::EQ, Token::NEQ, Token::LT, Token::LTE, Token::GT, Token::GTE,
235
+ Token::Contains, Token::Matches, Token::Like
236
+ operator = @token.value
237
+ next_token
238
+ right = parse_column
239
+ raise ParseException.new "Expecting right exp" unless right
240
+ return BinaryExpression.new left, operator, right
241
+ when Token::Starts, Token::Ends
242
+ operator = "#{@token.value}_with".to_sym
243
+ next_token
244
+ check! Token::With
245
+ right = parse_column
246
+ raise ParseException.new "Expecting right exp" unless right
247
+ return BinaryExpression.new left, operator, right
248
+ else
249
+ raise ParseException.new "Expecting comparison"
250
+ end
251
+ end
252
+ end
253
+
254
+ def parse_columns(columns = [])
255
+ column = parse_column
256
+ return columns unless column
257
+
258
+ columns << column
259
+ while token_is! Token::COMMA
260
+ column = parse_column
261
+ break unless column
262
+ columns << column
263
+ end
264
+ columns
265
+ end
266
+
267
+ def parse_column
268
+ parse_arithmetic_expression
269
+ end
270
+
271
+ def parse_arithmetic_expression
272
+ parse_summation_or_substraction
273
+ end
274
+
275
+ def parse_summation_or_substraction
276
+ column1 = parse_multiplication_or_divition
277
+ case @token.value
278
+ when Token::PLUS
279
+ next_token
280
+ column2 = parse_multiplication_or_divition
281
+ ScalarFunctionColumn.new ScalarFunctionColumn::Sum, column1, column2
282
+ when Token::MINUS
283
+ next_token
284
+ column2 = parse_multiplication_or_divition
285
+ ScalarFunctionColumn.new ScalarFunctionColumn::Difference, column1, column2
286
+ else
287
+ column1
288
+ end
289
+ end
290
+
291
+ def parse_multiplication_or_divition
292
+ column1 = parse_atomic_column
293
+ case @token.value
294
+ when Token::STAR
295
+ next_token
296
+ column2 = parse_atomic_column
297
+ ScalarFunctionColumn.new ScalarFunctionColumn::Product, column1, column2
298
+ when Token::SLASH
299
+ next_token
300
+ column2 = parse_atomic_column
301
+ ScalarFunctionColumn.new ScalarFunctionColumn::Quotient, column1, column2
302
+ else
303
+ column1
304
+ end
305
+ end
306
+
307
+ def parse_atomic_column
308
+ case @token.value
309
+ when Token::ID
310
+ return value_column(IdColumn.new @token.string)
311
+ when Token::Contains, Token::Starts, Token::Ends, Token::With,
312
+ Token::Matches, Token::Like, Token::NoValues, Token::NoFormat,
313
+ Token::Is, Token::Null
314
+ return value_column(IdColumn.new @token.value.to_s)
315
+ when Token::PLUS
316
+ next_token
317
+ check Token::INTEGER, Token::DECIMAL
318
+ return value_column(NumberColumn.new @token.number)
319
+ when Token::MINUS
320
+ next_token
321
+ check Token::INTEGER, Token::DECIMAL
322
+ return value_column(NumberColumn.new -@token.number)
323
+ when Token::INTEGER, Token::DECIMAL
324
+ return value_column(NumberColumn.new @token.number)
325
+ when Token::LPAREN
326
+ next_token
327
+ column = parse_column
328
+ check! Token::RPAREN
329
+ return column
330
+ when Token::STRING
331
+ return value_column(StringColumn.new @token.string)
332
+ when Token::False
333
+ return value_column(BooleanColumn.new false)
334
+ when Token::True
335
+ return value_column(BooleanColumn.new true)
336
+ when Token::Date
337
+ next_token
338
+ check Token::STRING
339
+ return value_column(DateColumn.new Date.parse(@token.string))
340
+ when Token::DateTime
341
+ next_token
342
+ check Token::STRING
343
+ return value_column(DateTimeColumn.new Time.parse(@token.string))
344
+ when Token::TimeOfDay
345
+ next_token
346
+ check Token::STRING
347
+ return value_column(TimeOfDayColumn.new Time.parse(@token.string))
348
+ when Token::Avg, Token::Count, Token::Min, Token::Max, Token::Sum
349
+ function = @token.value
350
+ next_token
351
+ if token_is! Token::LPAREN
352
+ column = parse_column
353
+ check! Token::RPAREN
354
+ return AggregateColumn.new function, column
355
+ else
356
+ return IdColumn.new function.to_s
357
+ end
358
+ when Token::Year, Token::Month, Token::Day,
359
+ Token::Hour, Token::Minute, Token::Second, Token::Millisecond,
360
+ Token::Now, Token::DateDiff, Token::Lower, Token::Upper,
361
+ Token::Quarter, Token::DayOfWeek, Token::ToDate
362
+ function = @token.value
363
+ next_token
364
+ if token_is! Token::LPAREN
365
+ columns = parse_columns
366
+ check! Token::RPAREN
367
+ return ScalarFunctionColumn.new function, *columns
368
+ else
369
+ return IdColumn.new function.to_s
370
+ end
371
+ end
372
+ nil
373
+ end
374
+
375
+ def value_column(col)
376
+ column = col
377
+ next_token
378
+ return column
379
+ end
380
+
381
+ def token_is?(token_value)
382
+ @token.value == token_value
383
+ end
384
+
385
+ def token_is!(token_value)
386
+ if @token.value == token_value
387
+ next_token
388
+ true
389
+ else
390
+ false
391
+ end
392
+ end
393
+
394
+ def check(*token_values)
395
+ raise ParseException.new "Expecting token #{token_values}" unless token_values.any?{|value| @token.value == value}
396
+ end
397
+
398
+ def check!(*token_values)
399
+ check *token_values
400
+ next_token
401
+ end
402
+ end
403
+ end
@@ -0,0 +1,83 @@
1
+ module Rgviz
2
+ class Token
3
+
4
+ And = :and
5
+ Asc = :asc
6
+ Avg = :avg
7
+ By = :by
8
+ Contains = :contains
9
+ Count = :count
10
+ Desc = :desc
11
+ Date = :date
12
+ DateDiff = :datediff
13
+ DateTime = :datetime
14
+ Day = :day
15
+ DayOfWeek = :dayofweek
16
+ Ends = :ends
17
+ False = :false
18
+ Format = :format
19
+ Group = :group
20
+ Hour = :hour
21
+ Is = :is
22
+ Label = :label
23
+ Like = :like
24
+ Limit = :limit
25
+ Lower = :lower
26
+ Matches = :matches
27
+ Millisecond = :millisecond
28
+ Min = :min
29
+ Minute = :minute
30
+ Max = :max
31
+ Month = :month
32
+ Not = :not
33
+ Now = :now
34
+ NoFormat = :no_format
35
+ NoValues = :no_values
36
+ Null = :null
37
+ Offset = :offset
38
+ Options = :options
39
+ Or = :or
40
+ Order = :order
41
+ Pivot = :pivot
42
+ Quarter = :quarter
43
+ Second = :second
44
+ Select = :select
45
+ Starts = :starts
46
+ Sum = :sum
47
+ TimeOfDay = :timeofday
48
+ Timestamp = :timestamp
49
+ ToDate = :todate
50
+ True = :true
51
+ Upper = :upper
52
+ Where = :where
53
+ With = :with
54
+ Year = :year
55
+
56
+ ID = :ID
57
+ INTEGER = :INTEGER
58
+ DECIMAL = :DECIMAL
59
+ STRING = :STRING
60
+
61
+ PLUS = :PLUS
62
+ MINUS = :MINUS
63
+ STAR = :STAR
64
+ SLASH = :SLASH
65
+
66
+ COMMA = :COMMA
67
+ LPAREN = :LPAREN
68
+ RPAREN = :RPAREN
69
+ EQ = :EQ
70
+ LT = :LT
71
+ LTE = :LTE
72
+ GT = :GT
73
+ GTE = :GTE
74
+ NEQ = :NEQ
75
+
76
+ EOF = :EOF
77
+
78
+ attr_accessor :start
79
+ attr_accessor :value
80
+ attr_accessor :string
81
+ attr_accessor :number
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ module Rgviz
2
+ class Visitor
3
+ ['Query', 'Select', 'GroupBy', 'Pivot', 'OrderBy',
4
+ 'Sort', 'Where', 'Label', 'Format', 'Option',
5
+ 'BinaryExpression', 'UnaryExpression',
6
+ 'IdColumn', 'NumberColumn', 'StringColumn',
7
+ 'BooleanColumn', 'DateColumn', 'DateTimeColumn',
8
+ 'TimeOfDayColumn', 'ScalarFunctionColumn', 'AggregateColumn'].each do |name|
9
+ define_method "visit#{name}" do |node|
10
+ true
11
+ end
12
+
13
+ define_method "endVisit#{name}" do |node|
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgviz
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
- version: "0.2"
8
+ - 3
9
+ version: "0.3"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ary Borenszweig
@@ -28,6 +28,11 @@ extra_rdoc_files: []
28
28
 
29
29
  files:
30
30
  - lib/rgviz.rb
31
+ - lib/rgviz/lexer.rb
32
+ - lib/rgviz/nodes.rb
33
+ - lib/rgviz/parser.rb
34
+ - lib/rgviz/token.rb
35
+ - lib/rgviz/visitor.rb
31
36
  has_rdoc: true
32
37
  homepage: http://code.google.com/p/rgviz
33
38
  licenses: []