gql 0.0.1

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,281 @@
1
+ class GQL::Parser
2
+ token STRING NUMBER TRUE FALSE NULL AS IDENT
3
+ rule
4
+ query
5
+ : variables call variables { result = QueryNode.new(val[1], convert_variables(val[0], val[2])) }
6
+ ;
7
+
8
+ call
9
+ : identifier arguments fields { result = CallNode.new(val[0], val[1], nil, val[2].presence) }
10
+ | identifier arguments sub_call { result = CallNode.new(val[0], val[1], val[2], nil) }
11
+ | identifier arguments { result = CallNode.new(val[0], val[1], nil, nil) }
12
+ ;
13
+
14
+ sub_call
15
+ : '.' call { result = val[1] }
16
+ ;
17
+
18
+ arguments
19
+ : /* empty */ { result = [] }
20
+ | '(' ')' { result = [] }
21
+ | '(' argument_list ')' { result = val[1] }
22
+ ;
23
+
24
+ argument_list
25
+ : argument_list ',' argument { result.push val[2] }
26
+ | argument { result = val }
27
+ ;
28
+
29
+ argument
30
+ : variable_identifier
31
+ | json_text
32
+ ;
33
+
34
+ fields
35
+ : '{' '}' { result = [] }
36
+ | '{' field_list '}' { result = val[1] }
37
+ ;
38
+
39
+ field_list
40
+ : field_list ',' field { result.push val[2] }
41
+ | field { result = val }
42
+ ;
43
+
44
+ field
45
+ : identifier fields alias_identifier { result = FieldNode.new(val[0], val[2], nil, val[1].presence) }
46
+ | identifier sub_call alias_identifier { result = FieldNode.new(val[0], val[2], val[1], nil) }
47
+ | identifier alias_identifier { result = FieldNode.new(val[0], val[1], nil, nil) }
48
+ | identifier fields { result = FieldNode.new(val[0], nil, nil, val[1].presence) }
49
+ | identifier sub_call { result = FieldNode.new(val[0], nil, val[1], nil) }
50
+ | identifier { result = FieldNode.new(val[0], nil, nil, nil) }
51
+ ;
52
+
53
+ alias_identifier
54
+ : AS identifier { result = val[1] }
55
+ ;
56
+
57
+ variables
58
+ : /* empty */ { result = [] }
59
+ | variable_list { result = val[0] }
60
+ ;
61
+
62
+ variable_list
63
+ : variable { result = val }
64
+ | variable_list variable { result.push val[1] }
65
+ ;
66
+
67
+ variable
68
+ : variable_identifier '=' variable_value { result = [val[0], val[2]] }
69
+ ;
70
+
71
+ variable_identifier
72
+ : '<' identifier '>' { result = val[1] }
73
+ ;
74
+
75
+ variable_value
76
+ : json_text
77
+ ;
78
+
79
+ json_text
80
+ : json_value { result = @json.result }
81
+
82
+ json_value
83
+ : object
84
+ | array
85
+ | scalar
86
+ ;
87
+
88
+ object
89
+ : start_object end_object
90
+ | start_object pairs end_object
91
+ ;
92
+
93
+ start_object : '{' { @json.start_object } ;
94
+ end_object : '}' { @json.end_object } ;
95
+
96
+ pairs
97
+ : pairs ',' pair
98
+ | pair
99
+ ;
100
+
101
+ pair
102
+ : string ':' json_value
103
+ ;
104
+
105
+ array
106
+ : start_array end_array
107
+ | start_array values end_array
108
+ ;
109
+
110
+ start_array : '[' { @json.start_array } ;
111
+ end_array : ']' { @json.end_array } ;
112
+
113
+ values
114
+ : values ',' json_value
115
+ | json_value
116
+ ;
117
+
118
+ scalar
119
+ : string
120
+ | literal { @json.scalar val[0] }
121
+ ;
122
+
123
+ string
124
+ : STRING { @json.scalar unescape_string(val[0]) }
125
+ ;
126
+
127
+ literal
128
+ : NUMBER { result = convert_number(val[0]) }
129
+ | TRUE { result = true }
130
+ | FALSE { result = false }
131
+ | NULL { result = nil }
132
+ ;
133
+
134
+ identifier
135
+ : IDENT { result = val[0].to_sym }
136
+ ;
137
+ end
138
+
139
+ ---- header
140
+
141
+ require 'json'
142
+ require 'active_support/core_ext/object/blank'
143
+
144
+ ---- inner
145
+
146
+ class QueryNode < Struct.new(:call, :variables)
147
+ end
148
+
149
+ class FieldNode < Struct.new(:name, :alias_name, :call, :fields)
150
+ end
151
+
152
+ class CallNode < Struct.new(:name, :arguments, :call, :fields)
153
+ end
154
+
155
+ class JSONHandler
156
+ attr_reader :stack
157
+
158
+ def initialize
159
+ clear
160
+ end
161
+
162
+ def start_object
163
+ push [:hash]
164
+ end
165
+
166
+ def start_array
167
+ push [:array]
168
+ end
169
+
170
+ def end_array
171
+ @stack.pop
172
+ end
173
+
174
+ alias :end_object :end_array
175
+
176
+ def scalar(s)
177
+ @stack.last << [:scalar, s]
178
+ end
179
+
180
+ def push(o)
181
+ @stack.last << o
182
+ @stack << o
183
+ end
184
+
185
+ def result
186
+ root = @stack.first.last
187
+ value = process(root.first, root.drop(1))
188
+ clear
189
+ value
190
+ end
191
+
192
+ private
193
+ def clear
194
+ @stack = [[:json]]
195
+ end
196
+
197
+ def process(type, rest)
198
+ case type
199
+ when :array
200
+ rest.map { |x| process(x.first, x.drop(1)) }
201
+ when :hash
202
+ Hash[rest.map { |x|
203
+ process(x.first, x.drop(1))
204
+ }.each_slice(2).to_a]
205
+ when :scalar
206
+ rest.first
207
+ end
208
+ end
209
+ end
210
+
211
+ UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
212
+
213
+ UNESCAPE_MAP.update(
214
+ ?" => '"',
215
+ ?\\ => '\\',
216
+ ?/ => '/',
217
+ ?b => "\b",
218
+ ?f => "\f",
219
+ ?n => "\n",
220
+ ?r => "\r",
221
+ ?t => "\t",
222
+ ?u => nil,
223
+ )
224
+
225
+ EMPTY_8BIT_STRING = ''
226
+
227
+ if String.method_defined? :encode
228
+ EMPTY_8BIT_STRING.force_encoding Encoding::ASCII_8BIT
229
+ end
230
+
231
+ def initialize(tokenizer)
232
+ super()
233
+
234
+ @tokenizer = tokenizer
235
+ end
236
+
237
+ def next_token
238
+ @tokenizer.next_token
239
+ end
240
+
241
+ def parse
242
+ @json = JSONHandler.new
243
+ do_parse
244
+ end
245
+
246
+ def on_error(token, value, vstack)
247
+ raise Errors::ParseError.new(value, token_to_str(token))
248
+ end
249
+
250
+ private
251
+ def unescape_string(str)
252
+ string = str.gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
253
+ if u = UNESCAPE_MAP[$&[1]]
254
+ u
255
+ else # \uXXXX
256
+ bytes = EMPTY_8BIT_STRING.dup
257
+ i = 0
258
+
259
+ while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
260
+ bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
261
+ i += 1
262
+ end
263
+
264
+ JSON.iconv('utf-8', 'utf-16be', bytes)
265
+ end
266
+ end
267
+
268
+ if string.respond_to? :force_encoding
269
+ string.force_encoding ::Encoding::UTF_8
270
+ end
271
+
272
+ string
273
+ end
274
+
275
+ def convert_number(str)
276
+ str.count('.') > 0 ? str.to_f : str.to_i
277
+ end
278
+
279
+ def convert_variables(arr1, arr2)
280
+ Hash[*arr1.flatten(1)].merge Hash[*arr2.flatten(1)]
281
+ end
@@ -0,0 +1,21 @@
1
+ require 'singleton'
2
+ require 'forwardable'
3
+
4
+ module GQL
5
+ class Schema
6
+ include Singleton
7
+
8
+ class << self
9
+ extend Forwardable
10
+
11
+ delegate [:root, :root=, :fields] => :instance
12
+ end
13
+
14
+ attr_accessor :root
15
+ attr_reader :fields
16
+
17
+ def initialize
18
+ @fields = {}
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,130 @@
1
+ #--
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.5
4
+ # from lexical definition file "lib/gql/tokenizer.rex".
5
+ #++
6
+
7
+ require 'racc/parser'
8
+ class GQL::Tokenizer < Racc::Parser
9
+ require 'strscan'
10
+
11
+ class ScanError < StandardError ; end
12
+
13
+ attr_reader :lineno
14
+ attr_reader :filename
15
+ attr_accessor :state
16
+
17
+ def scan_setup(str)
18
+ @ss = StringScanner.new(str)
19
+ @lineno = 1
20
+ @state = nil
21
+ end
22
+
23
+ def action
24
+ yield
25
+ end
26
+
27
+ def scan_str(str)
28
+ scan_setup(str)
29
+ do_parse
30
+ end
31
+ alias :scan :scan_str
32
+
33
+ def load_file( filename )
34
+ @filename = filename
35
+ open(filename, "r") do |f|
36
+ scan_setup(f.read)
37
+ end
38
+ end
39
+
40
+ def scan_file( filename )
41
+ load_file(filename)
42
+ do_parse
43
+ end
44
+
45
+
46
+ def next_token
47
+ return if @ss.eos?
48
+
49
+ # skips empty actions
50
+ until token = _next_token or @ss.eos?; end
51
+ token
52
+ end
53
+
54
+ def _next_token
55
+ text = @ss.peek(1)
56
+ @lineno += 1 if text == "\n"
57
+ token = case @state
58
+ when nil
59
+ case
60
+ when (text = @ss.scan(/\/\*/))
61
+ action { @state = :REMS; nil }
62
+
63
+ when (text = @ss.scan(/\/\//))
64
+ action { @state = :REM; nil }
65
+
66
+ when (text = @ss.scan(/"(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*"/))
67
+ action { [:STRING, text.gsub(/^"|"$/, '')] }
68
+
69
+ when (text = @ss.scan(/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/))
70
+ action { [:NUMBER, text] }
71
+
72
+ when (text = @ss.scan(/true/))
73
+ action { [:TRUE, text] }
74
+
75
+ when (text = @ss.scan(/false/))
76
+ action { [:FALSE, text] }
77
+
78
+ when (text = @ss.scan(/null/))
79
+ action { [:NULL, text] }
80
+
81
+ when (text = @ss.scan(/[aA][sS]/))
82
+ action { [:AS, text] }
83
+
84
+ when (text = @ss.scan(/[a-zA-Z_][a-zA-Z0-9_]*/))
85
+ action { [:IDENT, text] }
86
+
87
+ when (text = @ss.scan(/\s+/))
88
+ ;
89
+
90
+ when (text = @ss.scan(/./))
91
+ action { [text, text] }
92
+
93
+ else
94
+ text = @ss.string[@ss.pos .. -1]
95
+ raise ScanError, "can not match: '" + text + "'"
96
+ end # if
97
+
98
+ when :REMS
99
+ case
100
+ when (text = @ss.scan(/\*\//))
101
+ action { @state = nil; nil }
102
+
103
+ when (text = @ss.scan(/.*(?=\*\/)/))
104
+ ;
105
+
106
+ else
107
+ text = @ss.string[@ss.pos .. -1]
108
+ raise ScanError, "can not match: '" + text + "'"
109
+ end # if
110
+
111
+ when :REM
112
+ case
113
+ when (text = @ss.scan(/\n/))
114
+ action { @state = nil; nil }
115
+
116
+ when (text = @ss.scan(/.*(?=$)/))
117
+ ;
118
+
119
+ else
120
+ text = @ss.string[@ss.pos .. -1]
121
+ raise ScanError, "can not match: '" + text + "'"
122
+ end # if
123
+
124
+ else
125
+ raise ScanError, "undefined state: '" + state.to_s + "'"
126
+ end # case state
127
+ token
128
+ end # def _next_token
129
+
130
+ end # class
@@ -0,0 +1,46 @@
1
+ class GQL::Tokenizer
2
+ macro
3
+ BLANK \s+
4
+ REM_IN \/\*
5
+ REM_OUT \*\/
6
+ REM \/\/
7
+ STRING "(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4}))*"
8
+ NUMBER -?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?
9
+ TRUE true
10
+ FALSE false
11
+ NULL null
12
+ IDENT [a-zA-Z_][a-zA-Z0-9_]*
13
+ AS [aA][sS]
14
+
15
+ rule
16
+
17
+ # [:state] pattern [action]
18
+
19
+ # remarks
20
+ {REM_IN} { @state = :REMS; nil }
21
+ :REMS {REM_OUT} { @state = nil; nil }
22
+ :REMS .*(?={REM_OUT}) # ignore
23
+ {REM} { @state = :REM; nil }
24
+ :REM \n { @state = nil; nil }
25
+ :REM .*(?=$) # ignore
26
+
27
+ # scalars
28
+ {STRING} { [:STRING, text.gsub(/^"|"$/, '')] }
29
+ {NUMBER} { [:NUMBER, text] }
30
+ {TRUE} { [:TRUE, text] }
31
+ {FALSE} { [:FALSE, text] }
32
+ {NULL} { [:NULL, text] }
33
+
34
+ # keywords
35
+ {AS} { [:AS, text] }
36
+
37
+ # identifier
38
+ {IDENT} { [:IDENT, text] }
39
+
40
+ # whitespace
41
+ {BLANK} # ignore
42
+
43
+ # rest
44
+ . { [text, text] }
45
+
46
+ end