anbt-sql-formatter 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/anbt-sql-formatter +0 -3
- data/lib/anbt-sql-formatter/coarse-tokenizer.rb +1 -3
- data/lib/anbt-sql-formatter/exception.rb +0 -2
- data/lib/anbt-sql-formatter/formatter.rb +50 -57
- data/lib/anbt-sql-formatter/helper.rb +42 -56
- data/lib/anbt-sql-formatter/parser.rb +40 -52
- data/lib/anbt-sql-formatter/rule.rb +5 -2
- data/lib/anbt-sql-formatter/token.rb +1 -10
- data/lib/anbt-sql-formatter/version.rb +1 -1
- data/test/helper.rb +7 -1
- data/test/test_coarse-tokenizer.rb +327 -228
- data/test/test_formatter.rb +363 -276
- data/test/test_helper.rb +2 -2
- data/test/test_parser.rb +302 -213
- data/test/test_rule.rb +10 -8
- metadata +21 -31
data/bin/anbt-sql-formatter
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
#! /usr/bin/ruby1.8
|
2
2
|
# -*- coding: utf-8 -*-
|
3
3
|
|
4
|
-
require "pp"
|
5
|
-
|
6
4
|
begin
|
7
5
|
require "anbt-sql-formatter/formatter"
|
8
6
|
rescue LoadError
|
@@ -44,7 +42,6 @@ def main
|
|
44
42
|
formatter = AnbtSql::Formatter.new(rule)
|
45
43
|
result = formatter.format(src)
|
46
44
|
puts result
|
47
|
-
#pp result
|
48
45
|
end
|
49
46
|
|
50
47
|
main()
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
require "pp"
|
4
|
-
|
5
3
|
require "anbt-sql-formatter/rule"
|
6
4
|
require "anbt-sql-formatter/parser"
|
7
5
|
require "anbt-sql-formatter/exception"
|
@@ -11,6 +9,8 @@ require "anbt-sql-formatter/helper" # Stack
|
|
11
9
|
class AnbtSql
|
12
10
|
class Formatter
|
13
11
|
|
12
|
+
include StringUtil
|
13
|
+
|
14
14
|
@rule = nil
|
15
15
|
|
16
16
|
def initialize(rule)
|
@@ -49,7 +49,7 @@ class AnbtSql
|
|
49
49
|
@function_bracket.clear()
|
50
50
|
begin
|
51
51
|
isSqlEndsWithNewLine = false
|
52
|
-
if sql_str.
|
52
|
+
if sql_str.end_with?("\n")
|
53
53
|
isSqlEndsWithNewLine = true
|
54
54
|
end
|
55
55
|
|
@@ -103,8 +103,8 @@ class AnbtSql
|
|
103
103
|
tokens[index + 1].string == "+" &&
|
104
104
|
tokens[index + 2].string == ")")
|
105
105
|
tokens[index].string = "(+)"
|
106
|
-
|
107
|
-
|
106
|
+
ArrayUtil.remove(tokens, index + 1)
|
107
|
+
ArrayUtil.remove(tokens, index + 1)
|
108
108
|
end
|
109
109
|
index += 1
|
110
110
|
end
|
@@ -115,17 +115,17 @@ class AnbtSql
|
|
115
115
|
prevToken = nil
|
116
116
|
|
117
117
|
(tokens.size - 1).downto(1){|index|
|
118
|
-
token =
|
119
|
-
prevToken =
|
118
|
+
token = ArrayUtil.get(tokens, index)
|
119
|
+
prevToken = ArrayUtil.get(tokens, index - 1)
|
120
120
|
|
121
121
|
if (token._type == AnbtSql::TokenConstants::SPACE &&
|
122
122
|
(prevToken._type == AnbtSql::TokenConstants::SYMBOL ||
|
123
123
|
prevToken._type == AnbtSql::TokenConstants::COMMENT))
|
124
|
-
|
124
|
+
ArrayUtil.remove(tokens, index)
|
125
125
|
elsif ((token._type == AnbtSql::TokenConstants::SYMBOL ||
|
126
126
|
token._type == AnbtSql::TokenConstants::COMMENT) &&
|
127
127
|
prevToken._type == AnbtSql::TokenConstants::SPACE)
|
128
|
-
|
128
|
+
ArrayUtil.remove(tokens, index - 1)
|
129
129
|
elsif (token._type == AnbtSql::TokenConstants::SPACE)
|
130
130
|
token.string = " "
|
131
131
|
end
|
@@ -138,8 +138,8 @@ class AnbtSql
|
|
138
138
|
|
139
139
|
# Length of tokens changes in loop!
|
140
140
|
while index < tokens.size
|
141
|
-
prev =
|
142
|
-
token =
|
141
|
+
prev = ArrayUtil.get(tokens, index - 1)
|
142
|
+
token = ArrayUtil.get(tokens, index )
|
143
143
|
|
144
144
|
if (prev._type != AnbtSql::TokenConstants::SPACE &&
|
145
145
|
token._type != AnbtSql::TokenConstants::SPACE)
|
@@ -153,11 +153,11 @@ class AnbtSql
|
|
153
153
|
# 関数名の後ろにはスペースは入れない
|
154
154
|
# no space after function name
|
155
155
|
if (@rule.function?(prev.string) &&
|
156
|
-
token.string
|
156
|
+
token.string == "(")
|
157
157
|
index += 1 ; next
|
158
158
|
end
|
159
159
|
|
160
|
-
|
160
|
+
ArrayUtil.add(tokens, index,
|
161
161
|
AnbtSql::Token.new(AnbtSql::TokenConstants::SPACE, " ")
|
162
162
|
)
|
163
163
|
end
|
@@ -178,7 +178,7 @@ class AnbtSql
|
|
178
178
|
index = 0
|
179
179
|
# Length of tokens changes in loop!
|
180
180
|
while index < tokens.size
|
181
|
-
token =
|
181
|
+
token = ArrayUtil.get(tokens, index)
|
182
182
|
|
183
183
|
if token._type == AnbtSql::TokenConstants::SYMBOL # ****
|
184
184
|
|
@@ -208,61 +208,61 @@ class AnbtSql
|
|
208
208
|
elsif token._type == AnbtSql::TokenConstants::KEYWORD # ****
|
209
209
|
|
210
210
|
# indentを2つ増やし、キーワードの後ろで改行
|
211
|
-
if (token.string
|
212
|
-
token.string
|
213
|
-
token.string
|
211
|
+
if (equals_ignore_case(token.string, "DELETE") ||
|
212
|
+
equals_ignore_case(token.string, "SELECT") ||
|
213
|
+
equals_ignore_case(token.string, "UPDATE") )
|
214
214
|
indent += 2
|
215
215
|
index += insert_return_and_indent(tokens, index + 1, indent, "+2")
|
216
216
|
end
|
217
217
|
|
218
218
|
# indentを1つ増やし、キーワードの後ろで改行
|
219
|
-
if @rule.kw_plus1_indent_x_nl.any?{ |kw| token.string
|
219
|
+
if @rule.kw_plus1_indent_x_nl.any?{ |kw| equals_ignore_case(token.string, kw) }
|
220
220
|
indent += 1
|
221
221
|
index += insert_return_and_indent(tokens, index + 1, indent)
|
222
222
|
end
|
223
223
|
|
224
224
|
# キーワードの前でindentを1つ減らして改行、キーワードの後ろでindentを戻して改行。
|
225
|
-
if @rule.kw_minus1_indent_nl_x_plus1_indent.any?{ |kw| token.string
|
225
|
+
if @rule.kw_minus1_indent_nl_x_plus1_indent.any?{ |kw| equals_ignore_case(token.string, kw) }
|
226
226
|
index += insert_return_and_indent(tokens, index , indent - 1)
|
227
227
|
index += insert_return_and_indent(tokens, index + 1, indent )
|
228
228
|
end
|
229
229
|
|
230
230
|
# キーワードの前でindentを1つ減らして改行、キーワードの後ろでindentを戻して改行。
|
231
|
-
if (token.string
|
231
|
+
if (equals_ignore_case(token.string, "VALUES"))
|
232
232
|
indent -= 1
|
233
233
|
index += insert_return_and_indent(tokens, index, indent)
|
234
234
|
end
|
235
235
|
|
236
236
|
# キーワードの前でindentを1つ減らして改行
|
237
|
-
if (token.string
|
237
|
+
if (equals_ignore_case(token.string, "END"))
|
238
238
|
indent -= 1
|
239
239
|
index += insert_return_and_indent(tokens, index, indent)
|
240
240
|
end
|
241
241
|
|
242
242
|
# キーワードの前で改行
|
243
|
-
if @rule.kw_nl_x.any?{ |kw| token.string
|
243
|
+
if @rule.kw_nl_x.any?{ |kw| equals_ignore_case(token.string, kw) }
|
244
244
|
index += insert_return_and_indent(tokens, index, indent)
|
245
245
|
end
|
246
246
|
|
247
247
|
# キーワードの前で改行, インデント+1
|
248
|
-
if @rule.kw_nl_x_plus1_indent.any?{ |kw| token.string
|
248
|
+
if @rule.kw_nl_x_plus1_indent.any?{ |kw| equals_ignore_case(token.string, kw) }
|
249
249
|
index += insert_return_and_indent(tokens, index, indent + 1)
|
250
250
|
end
|
251
251
|
|
252
252
|
# キーワードの前で改行。indentを強制的に0にする。
|
253
|
-
if (token.string
|
254
|
-
token.string
|
255
|
-
token.string
|
253
|
+
if (equals_ignore_case(token.string, "UNION" ) ||
|
254
|
+
equals_ignore_case(token.string, "INTERSECT") ||
|
255
|
+
equals_ignore_case(token.string, "EXCEPT" ) )
|
256
256
|
indent -= 2
|
257
257
|
index += insert_return_and_indent(tokens, index , indent)
|
258
258
|
index += insert_return_and_indent(tokens, index + 1, indent)
|
259
259
|
end
|
260
260
|
|
261
|
-
if token.string
|
261
|
+
if equals_ignore_case(token.string, "BETWEEN")
|
262
262
|
encounterBetween = true
|
263
263
|
end
|
264
264
|
|
265
|
-
if token.string
|
265
|
+
if equals_ignore_case(token.string, "AND")
|
266
266
|
# BETWEEN のあとのANDは改行しない。
|
267
267
|
if not encounterBetween
|
268
268
|
index += insert_return_and_indent(tokens, index, indent)
|
@@ -272,10 +272,10 @@ class AnbtSql
|
|
272
272
|
|
273
273
|
elsif (token._type == AnbtSql::TokenConstants::COMMENT) # ****
|
274
274
|
|
275
|
-
if token.string.
|
275
|
+
if token.string.start_with?("/*")
|
276
276
|
# マルチラインコメントの後に改行を入れる。
|
277
277
|
index += insert_return_and_indent(tokens, index + 1, indent)
|
278
|
-
elsif
|
278
|
+
elsif token.string.start_with?("--")
|
279
279
|
index += insert_return_and_indent(tokens, index + 1, indent)
|
280
280
|
end
|
281
281
|
end
|
@@ -295,21 +295,21 @@ class AnbtSql
|
|
295
295
|
(tokens.size - 1).downto(4).each{|index|
|
296
296
|
next if (index >= tokens.size())
|
297
297
|
|
298
|
-
t0 =
|
299
|
-
t1 =
|
300
|
-
t2 =
|
301
|
-
t3 =
|
302
|
-
t4 =
|
298
|
+
t0 = ArrayUtil.get(tokens, index )
|
299
|
+
t1 = ArrayUtil.get(tokens, index - 1)
|
300
|
+
t2 = ArrayUtil.get(tokens, index - 2)
|
301
|
+
t3 = ArrayUtil.get(tokens, index - 3)
|
302
|
+
t4 = ArrayUtil.get(tokens, index - 4)
|
303
303
|
|
304
|
-
if (t4.string
|
305
|
-
t3.string.
|
306
|
-
t1.string.
|
307
|
-
t0.string
|
304
|
+
if (equals_ignore_case(t4.string , "(") &&
|
305
|
+
equals_ignore_case(t3.string.strip, "" ) &&
|
306
|
+
equals_ignore_case(t1.string.strip, "" ) &&
|
307
|
+
equals_ignore_case(t0.string , ")") )
|
308
308
|
t4.string = t4.string + t2.string + t0.string
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
309
|
+
ArrayUtil.remove(tokens, index )
|
310
|
+
ArrayUtil.remove(tokens, index - 1)
|
311
|
+
ArrayUtil.remove(tokens, index - 2)
|
312
|
+
ArrayUtil.remove(tokens, index - 3)
|
313
313
|
end
|
314
314
|
}
|
315
315
|
end
|
@@ -321,15 +321,15 @@ class AnbtSql
|
|
321
321
|
# SQLの前後に空白があったら削除する。
|
322
322
|
# Delete space token at first and last of SQL tokens.
|
323
323
|
|
324
|
-
token =
|
324
|
+
token = ArrayUtil.get(tokens, 0)
|
325
325
|
if (token._type == AnbtSql::TokenConstants::SPACE)
|
326
|
-
|
326
|
+
ArrayUtil.remove(tokens, 0)
|
327
327
|
end
|
328
328
|
return [] if tokens.empty?
|
329
329
|
|
330
|
-
token =
|
330
|
+
token = ArrayUtil.get(tokens, tokens.size() - 1)
|
331
331
|
if token._type == AnbtSql::TokenConstants::SPACE
|
332
|
-
|
332
|
+
ArrayUtil.remove(tokens, tokens.size() - 1)
|
333
333
|
end
|
334
334
|
return [] if tokens.empty?
|
335
335
|
|
@@ -361,33 +361,26 @@ class AnbtSql
|
|
361
361
|
begin
|
362
362
|
# 挿入する文字列を作成する。
|
363
363
|
s = "\n"
|
364
|
-
# もし1つ前にシングルラインコメントがあるなら、改行は不要。
|
365
|
-
prevToken = tokens.get(index - 1)
|
366
|
-
|
367
|
-
if (prevToken._type == AnbtSql::TokenConstants::COMMENT &&
|
368
|
-
prevToken.string.startsWith("--"))
|
369
|
-
s = ""
|
370
|
-
end
|
371
364
|
|
372
365
|
# インデントをつける。
|
373
366
|
indent = 0 if indent < 0 ## Java版と異なる
|
374
367
|
s += @rule.indent_string * indent
|
375
368
|
|
376
369
|
# 前後にすでにスペースがあれば、それを置き換える。
|
377
|
-
token =
|
370
|
+
token = ArrayUtil.get(tokens, index)
|
378
371
|
if token._type == AnbtSql::TokenConstants::SPACE
|
379
372
|
token.string = s
|
380
373
|
return 0
|
381
374
|
end
|
382
375
|
|
383
|
-
token =
|
376
|
+
token = ArrayUtil.get(tokens, index - 1)
|
384
377
|
if token._type == AnbtSql::TokenConstants::SPACE
|
385
378
|
token.string = s
|
386
379
|
return 0
|
387
380
|
end
|
388
381
|
|
389
382
|
# 前後になければ、新たにスペースを追加する。
|
390
|
-
|
383
|
+
ArrayUtil.add(tokens, index,
|
391
384
|
AnbtSql::Token.new(AnbtSql::TokenConstants::SPACE, s)
|
392
385
|
)
|
393
386
|
return 1
|
@@ -1,73 +1,59 @@
|
|
1
|
-
|
1
|
+
class AnbtSql
|
2
|
+
class Stack
|
3
|
+
include Enumerable
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@arr = []
|
8
|
-
end
|
9
|
-
|
10
|
-
def each
|
11
|
-
@arr.each{|item|
|
12
|
-
yield item
|
13
|
-
}
|
14
|
-
end
|
15
|
-
|
16
|
-
def clear
|
17
|
-
@arr.clear
|
18
|
-
end
|
19
|
-
|
20
|
-
def push(o)
|
21
|
-
@arr.push o
|
22
|
-
end
|
23
|
-
|
24
|
-
def pop
|
25
|
-
@arr.pop
|
26
|
-
end
|
27
|
-
end
|
5
|
+
def initialize
|
6
|
+
@arr = []
|
7
|
+
end
|
28
8
|
|
9
|
+
def each
|
10
|
+
@arr.each{|item|
|
11
|
+
yield item
|
12
|
+
}
|
13
|
+
end
|
29
14
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
15
|
+
def clear
|
16
|
+
@arr.clear
|
17
|
+
end
|
34
18
|
|
35
|
-
|
36
|
-
|
37
|
-
|
19
|
+
def push(o)
|
20
|
+
@arr.push o
|
21
|
+
end
|
38
22
|
|
39
|
-
|
40
|
-
|
23
|
+
def pop
|
24
|
+
@arr.pop
|
25
|
+
end
|
41
26
|
end
|
42
27
|
|
43
|
-
|
44
|
-
|
45
|
-
|
28
|
+
module StringUtil
|
29
|
+
def char_at(str, n)
|
30
|
+
if n < 0 || str.size - 1 < n
|
31
|
+
raise IndexOutOfBoundsException
|
32
|
+
end
|
46
33
|
|
47
|
-
|
48
|
-
|
49
|
-
end
|
34
|
+
str.slice(n, 1)
|
35
|
+
end
|
50
36
|
|
51
|
-
|
52
|
-
|
37
|
+
def equals_ignore_case(str_a, str_b)
|
38
|
+
str_a.casecmp(str_b) == 0
|
39
|
+
end
|
53
40
|
end
|
54
|
-
end
|
55
41
|
|
42
|
+
module ArrayUtil
|
43
|
+
def self.remove(ary, n)
|
44
|
+
ary.delete_at n
|
45
|
+
end
|
56
46
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
47
|
+
def self.get(ary, n)
|
48
|
+
if n < 0 || ary.size - 1 < n
|
49
|
+
raise IndexOutOfBoundsException
|
50
|
+
end
|
61
51
|
|
62
|
-
|
63
|
-
if n >= self.size || n <= -1
|
64
|
-
raise IndexOutOfBoundsException
|
52
|
+
ary[n]
|
65
53
|
end
|
66
54
|
|
67
|
-
self
|
68
|
-
|
69
|
-
|
70
|
-
def add(n,o)
|
71
|
-
self.insert(n,o)
|
55
|
+
def self.add(ary, n, o)
|
56
|
+
ary.insert(n, o)
|
57
|
+
end
|
72
58
|
end
|
73
59
|
end
|
@@ -10,6 +10,8 @@ require "anbt-sql-formatter/coarse-tokenizer"
|
|
10
10
|
class AnbtSql
|
11
11
|
class Parser
|
12
12
|
|
13
|
+
include ::AnbtSql::StringUtil
|
14
|
+
|
13
15
|
def initialize(rule)
|
14
16
|
@rule = rule
|
15
17
|
|
@@ -26,7 +28,7 @@ class AnbtSql
|
|
26
28
|
|
27
29
|
# 2文字からなる記号。
|
28
30
|
# なお、|| は文字列結合にあたります。
|
29
|
-
@two_character_symbol = [ "<>", "<=", ">=", "||" ]
|
31
|
+
@two_character_symbol = [ "<>", "<=", ">=", "||", "!=" ]
|
30
32
|
end
|
31
33
|
|
32
34
|
|
@@ -49,7 +51,7 @@ class AnbtSql
|
|
49
51
|
return false if space?(c)
|
50
52
|
return false if digit?(c)
|
51
53
|
return false if symbol?(c)
|
52
|
-
|
54
|
+
|
53
55
|
true
|
54
56
|
end
|
55
57
|
|
@@ -64,7 +66,7 @@ class AnbtSql
|
|
64
66
|
# アンダースコアは記号とは扱いません
|
65
67
|
# これ以降の文字の扱いは保留
|
66
68
|
def symbol?(c)
|
67
|
-
%w(" ? % & ' \( \) | * + , - . / : ; < = > ).include? c
|
69
|
+
%w(" ? % & ' \( \) | * + , - . / : ; < = > !).include? c
|
68
70
|
#"
|
69
71
|
end
|
70
72
|
|
@@ -80,35 +82,36 @@ class AnbtSql
|
|
80
82
|
$stderr.puts "next_token #{@pos} <#{@before}> #{@before.length}" if $DEBUG
|
81
83
|
|
82
84
|
start_pos = @pos
|
83
|
-
|
85
|
+
|
84
86
|
if @pos >= @before.length
|
85
87
|
@pos += 1
|
86
88
|
return nil
|
87
89
|
end
|
88
|
-
|
89
|
-
@char = @before
|
90
|
+
|
91
|
+
@char = char_at(@before, @pos)
|
90
92
|
|
91
93
|
if space?(@char)
|
92
94
|
workString = ""
|
93
|
-
loop {
|
95
|
+
loop {
|
94
96
|
workString += @char
|
95
97
|
|
96
|
-
|
97
|
-
if
|
98
|
-
@pos
|
99
|
-
|
100
|
-
workString, start_pos)
|
98
|
+
is_next_char_space = false
|
99
|
+
if @pos + 1 < @before.size &&
|
100
|
+
space?(char_at(@before, @pos+1))
|
101
|
+
is_next_char_space = true
|
101
102
|
end
|
102
103
|
|
103
|
-
|
104
|
-
|
105
|
-
if @pos >= @before.length()
|
104
|
+
if not is_next_char_space
|
105
|
+
@pos += 1
|
106
106
|
return AnbtSql::Token.new(AnbtSql::TokenConstants::SPACE,
|
107
|
-
|
107
|
+
workString, start_pos)
|
108
|
+
else
|
109
|
+
@pos += 1
|
110
|
+
next
|
108
111
|
end
|
109
112
|
}
|
110
113
|
|
111
|
-
|
114
|
+
|
112
115
|
elsif @char == ";"
|
113
116
|
@pos += 1
|
114
117
|
# 2005.07.26 Tosiki Iga セミコロンは終了扱いではないようにする。
|
@@ -116,66 +119,51 @@ class AnbtSql
|
|
116
119
|
";", start_pos)
|
117
120
|
|
118
121
|
elsif digit?(@char)
|
119
|
-
if
|
120
|
-
|
122
|
+
if /^(0x[0-9a-fA-F]+)/ =~ @before[@pos..-1] || # hex
|
123
|
+
/^(\d+(\.\d+(e-?\d+)?)?)/ =~ @before[@pos..-1] # integer, float or scientific
|
121
124
|
num = $1
|
122
125
|
@pos += num.length
|
123
126
|
return AnbtSql::Token.new(AnbtSql::TokenConstants::VALUE,
|
124
127
|
num, start_pos)
|
128
|
+
else
|
129
|
+
raise "must not happen"
|
125
130
|
end
|
126
131
|
|
127
|
-
s = ""
|
128
|
-
while (digit?(@char) || @char == '.')
|
129
|
-
# if (ch == '.') type = Token.REAL
|
130
|
-
s += @char
|
131
|
-
@pos += 1
|
132
|
-
|
133
|
-
if (@pos >= @before.length)
|
134
|
-
# 長さを超えている場合には処理中断します。
|
135
|
-
break
|
136
|
-
end
|
137
|
-
|
138
|
-
@char = @before.charAt(@pos)
|
139
|
-
end
|
140
|
-
return AnbtSql::Token.new(AnbtSql::TokenConstants::VALUE,
|
141
|
-
s, start_pos)
|
142
|
-
|
143
|
-
|
144
132
|
elsif letter?(@char)
|
145
133
|
s = ""
|
146
134
|
# 文字列中のドットについては、文字列と一体として考える。
|
147
|
-
while (letter?(@char) || digit?(@char) || @char == '.')
|
135
|
+
while (letter?(@char) || digit?(@char) || @char == '.')
|
148
136
|
s += @char
|
149
137
|
@pos += 1
|
150
138
|
if (@pos >= @before.length())
|
151
139
|
break
|
152
140
|
end
|
153
141
|
|
154
|
-
@char = @before
|
142
|
+
@char = char_at(@before, @pos)
|
155
143
|
end
|
156
144
|
|
157
145
|
if AnbtSql::Constants::SQL_RESERVED_WORDS.map{|w| w.upcase }.include?(s.upcase)
|
158
146
|
return AnbtSql::Token.new(AnbtSql::TokenConstants::KEYWORD,
|
159
147
|
s, start_pos)
|
160
148
|
end
|
161
|
-
|
149
|
+
|
162
150
|
return AnbtSql::Token.new(AnbtSql::TokenConstants::NAME,
|
163
151
|
s, start_pos)
|
164
152
|
|
165
153
|
elsif symbol?(@char)
|
166
154
|
s = "" + @char
|
167
155
|
@pos += 1
|
168
|
-
if (@pos >= @before.length())
|
156
|
+
if (@pos >= @before.length())
|
169
157
|
return AnbtSql::Token.new(AnbtSql::TokenConstants::SYMBOL,
|
170
158
|
s, start_pos)
|
171
159
|
end
|
172
160
|
|
173
161
|
# 2文字の記号かどうか調べる
|
174
|
-
ch2 = @before
|
162
|
+
ch2 = char_at(@before, @pos)
|
175
163
|
#for (int i = 0; i < two_character_symbol.length; i++) {
|
176
164
|
for i in 0...@two_character_symbol.length
|
177
|
-
if (@two_character_symbol[i]
|
178
|
-
@two_character_symbol[i]
|
165
|
+
if (char_at(@two_character_symbol[i], 0) == @char &&
|
166
|
+
char_at(@two_character_symbol[i], 1) == ch2)
|
179
167
|
@pos += 1
|
180
168
|
s += ch2
|
181
169
|
break
|
@@ -209,7 +197,7 @@ class AnbtSql
|
|
209
197
|
pos = 0
|
210
198
|
while pos < coarse_tokens.size
|
211
199
|
coarse_token = coarse_tokens[pos]
|
212
|
-
|
200
|
+
|
213
201
|
case coarse_token._type
|
214
202
|
|
215
203
|
when :quote_single
|
@@ -255,10 +243,10 @@ class AnbtSql
|
|
255
243
|
##
|
256
244
|
# 2つ以上並んだキーワードは1つのキーワードとみなします。
|
257
245
|
# ["a", " ", "group", " ", "by", " ", "b"]
|
258
|
-
# => ["a", " ", "group by", " ", "b"]
|
246
|
+
# => ["a", " ", "group by", " ", "b"]
|
259
247
|
def concat_multiwords_keyword(tokens)
|
260
248
|
temp_kw_list = @rule.kw_multi_words.map{|kw| kw.split(" ") }
|
261
|
-
|
249
|
+
|
262
250
|
# ワード数が多い順から
|
263
251
|
temp_kw_list.sort{ |a, b|
|
264
252
|
b.size <=> a.size
|
@@ -270,7 +258,7 @@ class AnbtSql
|
|
270
258
|
temp_tokens = tokens[index, target_tokens_size].map {|x|
|
271
259
|
x.string.sub(/\s+/, " ")
|
272
260
|
}
|
273
|
-
|
261
|
+
|
274
262
|
if /#{kw.join(" ")}/i =~ temp_tokens.join
|
275
263
|
tokens[index].string = temp_tokens.join
|
276
264
|
(target_tokens_size-1).downto(1).each{|c|
|
@@ -297,28 +285,28 @@ class AnbtSql
|
|
297
285
|
coarse_tokens = CoarseTokenizer.new.tokenize(sql_str)
|
298
286
|
|
299
287
|
prepare_tokens(coarse_tokens)
|
300
|
-
|
288
|
+
|
301
289
|
tokens = []
|
302
290
|
count = 0
|
303
291
|
@token_pos = 0
|
304
292
|
loop {
|
305
293
|
token = next_token()
|
306
|
-
|
294
|
+
|
307
295
|
if $DEBUG
|
308
296
|
pp "=" * 64, count, token, token.class
|
309
297
|
end
|
310
|
-
|
298
|
+
|
311
299
|
if token._type == AnbtSql::TokenConstants::END_OF_SQL
|
312
300
|
break
|
313
301
|
else
|
314
302
|
;
|
315
303
|
end
|
316
|
-
|
304
|
+
|
317
305
|
tokens.push token
|
318
306
|
count += 1
|
319
307
|
@token_pos += 1
|
320
308
|
}
|
321
|
-
|
309
|
+
|
322
310
|
concat_multiwords_keyword(tokens)
|
323
311
|
|
324
312
|
tokens
|