piggly 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/README.markdown +84 -0
  2. data/Rakefile +19 -0
  3. data/bin/piggly +245 -0
  4. data/lib/piggly/compiler/cache.rb +151 -0
  5. data/lib/piggly/compiler/pretty.rb +67 -0
  6. data/lib/piggly/compiler/queue.rb +46 -0
  7. data/lib/piggly/compiler/tags.rb +244 -0
  8. data/lib/piggly/compiler/trace.rb +91 -0
  9. data/lib/piggly/compiler.rb +5 -0
  10. data/lib/piggly/config.rb +43 -0
  11. data/lib/piggly/filecache.rb +40 -0
  12. data/lib/piggly/installer.rb +95 -0
  13. data/lib/piggly/parser/grammar.tt +747 -0
  14. data/lib/piggly/parser/nodes.rb +319 -0
  15. data/lib/piggly/parser/parser.rb +11783 -0
  16. data/lib/piggly/parser/traversal.rb +48 -0
  17. data/lib/piggly/parser/treetop_ruby19_patch.rb +17 -0
  18. data/lib/piggly/parser.rb +67 -0
  19. data/lib/piggly/profile.rb +87 -0
  20. data/lib/piggly/reporter/html.rb +207 -0
  21. data/lib/piggly/reporter/piggly.css +187 -0
  22. data/lib/piggly/reporter/sortable.js +493 -0
  23. data/lib/piggly/reporter.rb +21 -0
  24. data/lib/piggly/task.rb +64 -0
  25. data/lib/piggly/util.rb +28 -0
  26. data/lib/piggly/version.rb +15 -0
  27. data/lib/piggly.rb +18 -0
  28. data/spec/compiler/cache_spec.rb +9 -0
  29. data/spec/compiler/pretty_spec.rb +9 -0
  30. data/spec/compiler/queue_spec.rb +3 -0
  31. data/spec/compiler/rewrite_spec.rb +3 -0
  32. data/spec/compiler/tags_spec.rb +285 -0
  33. data/spec/compiler/trace_spec.rb +173 -0
  34. data/spec/config_spec.rb +58 -0
  35. data/spec/filecache_spec.rb +70 -0
  36. data/spec/fixtures/snippets.sql +158 -0
  37. data/spec/grammar/expression_spec.rb +302 -0
  38. data/spec/grammar/statements/assignment_spec.rb +70 -0
  39. data/spec/grammar/statements/exception_spec.rb +52 -0
  40. data/spec/grammar/statements/if_spec.rb +178 -0
  41. data/spec/grammar/statements/loop_spec.rb +41 -0
  42. data/spec/grammar/statements/sql_spec.rb +71 -0
  43. data/spec/grammar/tokens/comment_spec.rb +58 -0
  44. data/spec/grammar/tokens/datatype_spec.rb +52 -0
  45. data/spec/grammar/tokens/identifier_spec.rb +58 -0
  46. data/spec/grammar/tokens/keyword_spec.rb +44 -0
  47. data/spec/grammar/tokens/label_spec.rb +40 -0
  48. data/spec/grammar/tokens/literal_spec.rb +30 -0
  49. data/spec/grammar/tokens/lval_spec.rb +50 -0
  50. data/spec/grammar/tokens/number_spec.rb +34 -0
  51. data/spec/grammar/tokens/sqlkeywords_spec.rb +45 -0
  52. data/spec/grammar/tokens/string_spec.rb +54 -0
  53. data/spec/grammar/tokens/whitespace_spec.rb +40 -0
  54. data/spec/parser_spec.rb +8 -0
  55. data/spec/profile_spec.rb +5 -0
  56. data/spec/reporter/html_spec.rb +0 -0
  57. data/spec/spec_helper.rb +61 -0
  58. data/spec/spec_suite.rb +5 -0
  59. metadata +121 -0
@@ -0,0 +1,319 @@
1
+ require File.join(File.dirname(__FILE__), 'traversal')
2
+
3
+ NodeClass = Treetop::Runtime::SyntaxNode
4
+
5
+ class NodeClass
6
+ include Piggly::NodeTraversal
7
+
8
+ # The 'text_value' method can be used to read the parse tree as Treetop
9
+ # originally read it. The 'source_text' method returns redefined value or falls
10
+ # back to original text_value if none was set.
11
+
12
+ attr_accessor :source_text
13
+
14
+ def value
15
+ puts "NodeClass#value is deprecated: #{caller.first}"
16
+ text_value
17
+ end
18
+
19
+ def source_text
20
+ @source_text || text_value
21
+ end
22
+
23
+ #
24
+ # Return a newly created Tag value, but only the tag.id is attached to the tree. The
25
+ # reason that is we maintain the Tags in a separate collection (to avoid a full traversal
26
+ # just to get the list of tags later), and we can retrieve the Tag associated with this
27
+ # node by its tag_id.
28
+ #
29
+ def tag(prefix = nil, id = nil)
30
+ unless defined? @tag_id
31
+ if named?(:body)
32
+ Piggly::BlockTag.new(prefix, id)
33
+ else
34
+ Piggly::EvaluationTag.new(prefix, id)
35
+ end.tap{|tag| @tag_id = tag.id }
36
+ end
37
+ end
38
+
39
+ def tag_id
40
+ @tag_id or raise RuntimeError, "Node is not tagged"
41
+ end
42
+
43
+ def tagged?
44
+ not @tag_id.nil?
45
+ end
46
+
47
+ # overridden in subclasses
48
+ def expression?; false end
49
+ def branch?; false end
50
+ def block?; false end
51
+ def stub?; false end
52
+ def loop?; false end
53
+ def for?; false end
54
+ def style; nil end
55
+
56
+ def indent(method = nil)
57
+ if method and respond_to?(method)
58
+ send(method).text_value[/\n[\t ]*\z/]
59
+ else
60
+ text_value[/\n[\t ]*\z/]
61
+ end
62
+ end
63
+
64
+ alias o_inspect inspect
65
+
66
+ def inspect(indent = '')
67
+ if terminal?
68
+ em = extension_modules
69
+ interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods
70
+ im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : ""
71
+ tv = text_value
72
+ tv = "...#{tv[-20..-1]}" if tv.size > 20
73
+
74
+ indent +
75
+ self.class.to_s.sub(/.*:/,'') +
76
+ em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
77
+ " offset=#{interval.first}" +
78
+ ", #{tv.inspect}" +
79
+ im
80
+ else
81
+ o_inspect(indent)
82
+ end
83
+ end
84
+
85
+ # true if node is called 'label' in parent node
86
+ def named?(label)
87
+ if p = parent
88
+ p.respond_to?(label) and p.send(label).equal?(self)
89
+ end
90
+ end
91
+ end
92
+
93
+ module Piggly
94
+
95
+ # CREATE OR REPLACE ...
96
+ class Procedure < NodeClass
97
+ end
98
+
99
+ # ...;
100
+ class Statement < NodeClass
101
+ end
102
+
103
+ class Expression < NodeClass
104
+ def expression?
105
+ true
106
+ end
107
+
108
+ def tag(prefix = nil, id = nil)
109
+ unless defined? @tag_id
110
+ if named?(:cond)
111
+ if parent.for?
112
+ # this object is the conditional statement in a FOR loop
113
+ Piggly::ForCollectionTag.new(prefix, id)
114
+ elsif parent.loop?
115
+ # this object is the conditional statement in a WHILE loop
116
+ Piggly::LoopConditionTag.new(prefix, id)
117
+ elsif parent.branch?
118
+ Piggly::BranchConditionTag.new(prefix, id)
119
+ end
120
+ else
121
+ Piggly::Evaluation.new(prefix, id)
122
+ end.tap{|tag| @tag_id = tag.id }
123
+ end
124
+ end
125
+ end
126
+
127
+ # DECLARE declaration BEGIN body END;
128
+ class Block < Statement
129
+ def block?
130
+ true
131
+ end
132
+ end
133
+
134
+ # Branches with child 'cond' (Expression) will get a BranchCondTag
135
+ class Branch < Statement
136
+ def branch?
137
+ true
138
+ end
139
+ end
140
+
141
+ # IF boolean-cond THEN body
142
+ class If < Branch
143
+ end
144
+
145
+ # ELSE body END
146
+ class Else < NodeClass
147
+ end
148
+
149
+ # EXCEPTION WHEN boolean-cond THEN body
150
+ class Catch < Branch
151
+ end
152
+
153
+ # WHEN match-expr THEN body
154
+ class CaseWhen < Branch
155
+ end
156
+
157
+ # WHEN boolean-cond THEN body
158
+ class CondWhen < Branch
159
+ end
160
+
161
+ # CONTINUE label WHEN boolean-cond;
162
+ class ContinueWhen < Branch
163
+ end
164
+
165
+ # EXIT label WHEN boolean-cond;
166
+ class ExitWhen < Branch
167
+ end
168
+
169
+ class UnconditionalBranch < Statement
170
+ end
171
+
172
+ # RETURN expr
173
+ class Return < UnconditionalBranch
174
+ end
175
+
176
+ # EXIT label
177
+ class Exit < UnconditionalBranch
178
+ end
179
+
180
+ # CONTINUE label
181
+ class Continue < UnconditionalBranch
182
+ end
183
+
184
+ # RAISE EXCEPTION expr
185
+ class Throw < UnconditionalBranch
186
+ end
187
+
188
+ # Loops with child 'cond' (Expression/Sql) will get a LoopCondTag
189
+ class Loop < Statement
190
+ def loop?
191
+ true
192
+ end
193
+ end
194
+
195
+ # FOR boolean-cond LOOP body END
196
+ class ForLoop < Loop
197
+ def for?; true end
198
+ end
199
+
200
+ # WHILE boolean-cond LOOP body END
201
+ class WhileLoop < Loop
202
+ end
203
+
204
+
205
+ # RAISE NOTICE expr
206
+ class Raise < Statement
207
+ end
208
+
209
+ # CASE search-expr WHEN ...
210
+ class Case < Statement
211
+ end
212
+
213
+ # CASE WHEN ...
214
+ class Cond < Statement
215
+ end
216
+
217
+ # lval := rval
218
+ class Assignment < Statement
219
+ end
220
+
221
+ # Lval of assignment (rval is an Expression)
222
+ class Assignable < NodeClass
223
+ end
224
+
225
+ class Sql < Statement
226
+ def style; 'tQ'; end
227
+
228
+ def tag(prefix = nil, id = nil)
229
+ unless defined? @tag_id
230
+ if named?(:cond) and parent.for?
231
+ # this object is the conditional statement in a FOR loop
232
+ Piggly::ForCollectionTag.new(prefix, id)
233
+ else
234
+ Piggly::EvaluationTag.new(prefix, id)
235
+ end.tap{|tag| @tag_id = tag.id }
236
+ end
237
+ end
238
+ end
239
+
240
+ # Tokens have no children
241
+ class Token < NodeClass
242
+ def initialize(input, interval, elements = nil)
243
+ # prevent children from being assigned
244
+ super(input, interval, nil)
245
+ end
246
+
247
+ def terminal?
248
+ true
249
+ end
250
+ end
251
+
252
+ # This seems like it should be a Token, but it may contain TComment children
253
+ # that should be highlighted differently than the enclosing whitespace
254
+ class TWhitespace < NodeClass
255
+ end
256
+
257
+ class TKeyword < Token
258
+ def style; 'tK'; end
259
+ end
260
+
261
+ class TIdentifier < Token
262
+ def style; 'tI'; end
263
+ end
264
+
265
+ class TDatatype < Token
266
+ def style; 'tD'; end
267
+ end
268
+
269
+ class TString < Token
270
+ def style; 'tS'; end
271
+ end
272
+
273
+ class TDollarQuoteMarker < Token
274
+ def style; 'tM'; end
275
+ end
276
+
277
+ class TComment < Token
278
+ def style; 'tC'; end
279
+ end
280
+
281
+ class TLabel < Token
282
+ def style; 'tL'; end
283
+ end
284
+
285
+ # Text nodes have no children
286
+ class TextNode < NodeClass
287
+ def initialize(input, interval, elements = nil)
288
+ # prevent children from being assigned
289
+ super(input, interval, nil)
290
+ end
291
+
292
+ def terminal?
293
+ true
294
+ end
295
+ end
296
+
297
+ # Stub nodes have no children, or content
298
+ class StubNode < NodeClass
299
+ def initialize(input, interval, elements = nil)
300
+ # prevent children from being assigned
301
+ super(input, interval, nil)
302
+ end
303
+
304
+ def terminal?
305
+ true
306
+ end
307
+
308
+ def stub?
309
+ true
310
+ end
311
+ end
312
+
313
+ class NotImplemented < NodeClass
314
+ def parent=(object)
315
+ # this would go in the constructor, but parent is set from outside
316
+ raise Piggly::Parser::Failure, "Grammar does not implement #{object.source_text} at line #{input.line_of(object.interval.first)}"
317
+ end
318
+ end
319
+ end