piggly 1.2.1 → 2.0.0

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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +163 -0
  3. data/Rakefile +29 -15
  4. data/bin/piggly +4 -244
  5. data/lib/piggly.rb +19 -17
  6. data/lib/piggly/command.rb +9 -0
  7. data/lib/piggly/command/base.rb +148 -0
  8. data/lib/piggly/command/report.rb +162 -0
  9. data/lib/piggly/command/test.rb +157 -0
  10. data/lib/piggly/command/trace.rb +90 -0
  11. data/lib/piggly/command/untrace.rb +78 -0
  12. data/lib/piggly/compiler.rb +7 -5
  13. data/lib/piggly/compiler/cache_dir.rb +119 -0
  14. data/lib/piggly/compiler/coverage_report.rb +63 -0
  15. data/lib/piggly/compiler/trace_compiler.rb +105 -0
  16. data/lib/piggly/config.rb +47 -22
  17. data/lib/piggly/dumper.rb +9 -0
  18. data/lib/piggly/dumper/index.rb +121 -0
  19. data/lib/piggly/dumper/qualified_name.rb +36 -0
  20. data/lib/piggly/dumper/qualified_type.rb +81 -0
  21. data/lib/piggly/dumper/reified_procedure.rb +142 -0
  22. data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
  23. data/lib/piggly/installer.rb +84 -42
  24. data/lib/piggly/parser.rb +43 -49
  25. data/lib/piggly/parser/grammar.tt +289 -313
  26. data/lib/piggly/parser/nodes.rb +270 -211
  27. data/lib/piggly/parser/traversal.rb +35 -33
  28. data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
  29. data/lib/piggly/profile.rb +81 -60
  30. data/lib/piggly/reporter.rb +5 -18
  31. data/lib/piggly/reporter/base.rb +103 -0
  32. data/lib/piggly/reporter/html_dsl.rb +63 -0
  33. data/lib/piggly/reporter/index.rb +108 -0
  34. data/lib/piggly/reporter/procedure.rb +104 -0
  35. data/lib/piggly/reporter/resources/highlight.js +21 -0
  36. data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
  37. data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
  38. data/lib/piggly/tags.rb +280 -0
  39. data/lib/piggly/task.rb +191 -40
  40. data/lib/piggly/util.rb +8 -27
  41. data/lib/piggly/util/blankslate.rb +114 -0
  42. data/lib/piggly/util/cacheable.rb +19 -0
  43. data/lib/piggly/util/enumerable.rb +44 -0
  44. data/lib/piggly/util/file.rb +17 -0
  45. data/lib/piggly/util/process_queue.rb +96 -0
  46. data/lib/piggly/util/thunk.rb +39 -0
  47. data/lib/piggly/version.rb +8 -8
  48. data/spec/examples/compiler/cacheable_spec.rb +190 -0
  49. data/spec/examples/compiler/report_spec.rb +25 -0
  50. data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
  51. data/spec/examples/config_spec.rb +61 -0
  52. data/spec/examples/dumper/index_spec.rb +197 -0
  53. data/spec/examples/dumper/procedure_spec.rb +116 -0
  54. data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
  55. data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
  56. data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
  57. data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
  58. data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
  59. data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
  60. data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
  61. data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
  62. data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
  63. data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
  64. data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
  65. data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
  66. data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
  67. data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
  68. data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
  69. data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
  70. data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
  71. data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
  72. data/spec/examples/installer_spec.rb +59 -0
  73. data/spec/examples/parser/nodes_spec.rb +73 -0
  74. data/spec/examples/parser/traversal_spec.rb +14 -0
  75. data/spec/examples/parser_spec.rb +115 -0
  76. data/spec/examples/profile_spec.rb +153 -0
  77. data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
  78. data/spec/examples/reporter/html/index_spec.rb +0 -0
  79. data/spec/examples/reporter/html_spec.rb +1 -0
  80. data/spec/examples/reporter_spec.rb +0 -0
  81. data/spec/{compiler → examples}/tags_spec.rb +10 -10
  82. data/spec/examples/task_spec.rb +0 -0
  83. data/spec/examples/util/cacheable_spec.rb +41 -0
  84. data/spec/examples/util/enumerable_spec.rb +64 -0
  85. data/spec/examples/util/file_spec.rb +40 -0
  86. data/spec/examples/util/process_queue_spec.rb +16 -0
  87. data/spec/examples/util/thunk_spec.rb +58 -0
  88. data/spec/examples/version_spec.rb +0 -0
  89. data/spec/issues/007_spec.rb +25 -0
  90. data/spec/issues/008_spec.rb +73 -0
  91. data/spec/issues/018_spec.rb +25 -0
  92. data/spec/spec_helper.rb +253 -9
  93. metadata +136 -93
  94. data/README.markdown +0 -116
  95. data/lib/piggly/compiler/cache.rb +0 -151
  96. data/lib/piggly/compiler/pretty.rb +0 -67
  97. data/lib/piggly/compiler/queue.rb +0 -46
  98. data/lib/piggly/compiler/tags.rb +0 -244
  99. data/lib/piggly/compiler/trace.rb +0 -91
  100. data/lib/piggly/filecache.rb +0 -40
  101. data/lib/piggly/parser/parser.rb +0 -11794
  102. data/lib/piggly/reporter/html.rb +0 -207
  103. data/spec/compiler/cache_spec.rb +0 -9
  104. data/spec/compiler/pretty_spec.rb +0 -9
  105. data/spec/compiler/queue_spec.rb +0 -3
  106. data/spec/compiler/rewrite_spec.rb +0 -3
  107. data/spec/config_spec.rb +0 -58
  108. data/spec/filecache_spec.rb +0 -70
  109. data/spec/fixtures/snippets.sql +0 -158
  110. data/spec/grammar/tokens/lval_spec.rb +0 -50
  111. data/spec/parser_spec.rb +0 -8
  112. data/spec/profile_spec.rb +0 -5
@@ -1,9 +1,7 @@
1
- require File.join(File.dirname(__FILE__), 'traversal')
2
-
3
1
  NodeClass = Treetop::Runtime::SyntaxNode
4
2
 
5
3
  class NodeClass
6
- include Piggly::NodeTraversal
4
+ include Piggly::Parser::Traversal
7
5
 
8
6
  # The 'text_value' method can be used to read the parse tree as Treetop
9
7
  # originally read it. The 'source_text' method returns redefined value or falls
@@ -11,11 +9,6 @@ class NodeClass
11
9
 
12
10
  attr_accessor :source_text
13
11
 
14
- def value
15
- puts "NodeClass#value is deprecated: #{caller.first}"
16
- text_value
17
- end
18
-
19
12
  def source_text
20
13
  @source_text || text_value
21
14
  end
@@ -29,9 +22,9 @@ class NodeClass
29
22
  def tag(prefix = nil, id = nil)
30
23
  unless defined? @tag_id
31
24
  if named?(:body)
32
- Piggly::BlockTag.new(prefix, id)
25
+ Piggly::Tags::BlockTag.new(prefix, id)
33
26
  else
34
- Piggly::EvaluationTag.new(prefix, id)
27
+ Piggly::Tags::EvaluationTag.new(prefix, id)
35
28
  end.tap{|tag| @tag_id = tag.id }
36
29
  end
37
30
  end
@@ -41,7 +34,7 @@ class NodeClass
41
34
  end
42
35
 
43
36
  def tagged?
44
- not @tag_id.nil?
37
+ defined? @tag_id
45
38
  end
46
39
 
47
40
  # overridden in subclasses
@@ -51,38 +44,31 @@ class NodeClass
51
44
  def stub?; false end
52
45
  def loop?; false end
53
46
  def for?; false end
47
+ def while?; false end
54
48
  def style; nil end
49
+ def comment?; false end
50
+ def whitespace?; false end
51
+ def token?; false end
52
+ def string?; false end
53
+ def datatype?; false end
54
+ def identifier?; false end
55
+ def assignment?; false end
56
+ def sql?; false end
57
+ def statement?; false; end
58
+ def if?; false; end
59
+ def else?; false; end
60
+ def label?; false; end
61
+ def keyword?; false; end
55
62
 
56
63
  def indent(method = nil)
57
64
  if method and respond_to?(method)
58
65
  send(method).text_value[/\n[\t ]*\z/]
59
66
  else
60
67
  text_value[/\n[\t ]*\z/]
61
- end
68
+ end || ""
62
69
  end
63
70
 
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
71
+ # True if node is called `label` by the parent node
86
72
  def named?(label)
87
73
  if p = parent
88
74
  p.respond_to?(label) and p.send(label).equal?(self)
@@ -91,229 +77,302 @@ class NodeClass
91
77
  end
92
78
 
93
79
  module Piggly
80
+ module Parser
81
+ module Nodes
82
+
83
+ # ...;
84
+ class Statement < NodeClass
85
+ def statement?
86
+ true
87
+ end
88
+
89
+ def terminal?
90
+ false
91
+ end
92
+ end
94
93
 
95
- # CREATE OR REPLACE ...
96
- class Procedure < NodeClass
97
- end
94
+ class Expression < NodeClass
95
+ def expression?
96
+ true
97
+ end
98
+
99
+ def tag(prefix = nil, id = nil)
100
+ unless defined? @tag_id
101
+ if named?(:cond)
102
+ if parent.while?
103
+ # This node is the conditional in a WHILE loop
104
+ Tags::ConditionalLoopTag.new(prefix, id)
105
+ elsif parent.loop?
106
+ # This node is the conditional in a loop
107
+ Tags::UnconditionalLoopTag.new(prefix, id)
108
+ elsif parent.branch?
109
+ # This node is a conditional in a branch
110
+ Tags::ConditionalBranchTag.new(prefix, id)
111
+ else
112
+ Tags::EvaluationTag.new(prefix, id)
113
+ end
114
+ else
115
+ Tags::EvaluationTag.new(prefix, id)
116
+ end.tap{|tag| @tag_id = tag.id }
117
+ end
118
+ end
98
119
 
99
- # ...;
100
- class Statement < NodeClass
101
- end
120
+ def terminal?
121
+ false
122
+ end
123
+ end
102
124
 
103
- class Expression < NodeClass
104
- def expression?
105
- true
106
- end
125
+ # DECLARE declaration BEGIN body END;
126
+ class Block < Statement
127
+ def block?
128
+ true
129
+ end
130
+ end
107
131
 
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 }
132
+ # Branches with child 'cond' (Expression) will get a ConditionalBranchTag
133
+ class Branch < Statement
134
+ def branch?
135
+ true
136
+ end
123
137
  end
124
- end
125
- end
126
138
 
127
- # DECLARE declaration BEGIN body END;
128
- class Block < Statement
129
- def block?
130
- true
131
- end
132
- end
139
+ # IF boolean-cond THEN body
140
+ class If < Branch
141
+ def if?
142
+ true
143
+ end
133
144
 
134
- # Branches with child 'cond' (Expression) will get a BranchCondTag
135
- class Branch < Statement
136
- def branch?
137
- true
138
- end
139
- end
145
+ def terminal?
146
+ false
147
+ end
148
+ end
140
149
 
141
- # IF boolean-cond THEN body
142
- class If < Branch
143
- end
150
+ # ELSE body END
151
+ class Else < NodeClass
152
+ def else?
153
+ true
154
+ end
144
155
 
145
- # ELSE body END
146
- class Else < NodeClass
147
- end
156
+ def terminal?
157
+ false
158
+ end
159
+ end
148
160
 
149
- # EXCEPTION WHEN boolean-cond THEN body
150
- class Catch < Branch
151
- end
161
+ # EXCEPTION WHEN boolean-cond THEN body
162
+ class Catch < Branch
163
+ end
152
164
 
153
- # WHEN match-expr THEN body
154
- class CaseWhen < Branch
155
- end
165
+ # WHEN match-expr THEN body
166
+ class CaseWhen < Branch
167
+ end
156
168
 
157
- # WHEN boolean-cond THEN body
158
- class CondWhen < Branch
159
- end
169
+ # WHEN boolean-cond THEN body
170
+ class CondWhen < Branch
171
+ end
160
172
 
161
- # CONTINUE label WHEN boolean-cond;
162
- class ContinueWhen < Branch
163
- end
173
+ # CONTINUE label WHEN boolean-cond;
174
+ class ContinueWhen < Branch
175
+ end
164
176
 
165
- # EXIT label WHEN boolean-cond;
166
- class ExitWhen < Branch
167
- end
177
+ # EXIT label WHEN boolean-cond;
178
+ class ExitWhen < Branch
179
+ end
168
180
 
169
- class UnconditionalBranch < Statement
170
- end
181
+ class UnconditionalBranch < Statement
182
+ end
171
183
 
172
- # RETURN expr
173
- class Return < UnconditionalBranch
174
- end
184
+ # RETURN expr
185
+ class Return < UnconditionalBranch
186
+ end
175
187
 
176
- # EXIT label
177
- class Exit < UnconditionalBranch
178
- end
188
+ # EXIT label
189
+ class Exit < UnconditionalBranch
190
+ end
179
191
 
180
- # CONTINUE label
181
- class Continue < UnconditionalBranch
182
- end
192
+ # CONTINUE label
193
+ class Continue < UnconditionalBranch
194
+ end
183
195
 
184
- # RAISE EXCEPTION expr
185
- class Throw < UnconditionalBranch
186
- end
196
+ # RAISE EXCEPTION expr
197
+ class Throw < UnconditionalBranch
198
+ end
187
199
 
188
- # Loops with child 'cond' (Expression/Sql) will get a LoopCondTag
189
- class Loop < Statement
190
- def loop?
191
- true
192
- end
193
- end
200
+ # Loops that have a child named :cond (which should be either an Expression
201
+ # or Sql node) will get a LoopCondTag from the #tag method
202
+ class Loop < Statement
203
+ def loop?
204
+ true
205
+ end
206
+ end
194
207
 
195
- # FOR boolean-cond LOOP body END
196
- class ForLoop < Loop
197
- def for?; true end
198
- end
208
+ # FOR var IN expr LOOP body END
209
+ class ForLoop < Loop
210
+ def for?
211
+ true
212
+ end
213
+ end
199
214
 
200
- # WHILE boolean-cond LOOP body END
201
- class WhileLoop < Loop
202
- end
215
+ # FOREACH var IN ARRAY expr LOOP body END
216
+ class ForEachLoop < Loop
217
+ def for?
218
+ true
219
+ end
220
+ end
203
221
 
222
+ # WHILE boolean-cond LOOP body END
223
+ class WhileLoop < Loop
224
+ def while?
225
+ true
226
+ end
227
+ end
204
228
 
205
- # RAISE NOTICE expr
206
- class Raise < Statement
207
- end
208
229
 
209
- # CASE search-expr WHEN ...
210
- class Case < Statement
211
- end
230
+ # RAISE NOTICE expr
231
+ class Raise < Statement
232
+ end
212
233
 
213
- # CASE WHEN ...
214
- class Cond < Statement
215
- end
234
+ # CASE search-expr WHEN ...
235
+ class Case < Statement
236
+ end
216
237
 
217
- # lval := rval
218
- class Assignment < Statement
219
- end
238
+ # CASE WHEN ...
239
+ class Cond < Statement
240
+ end
220
241
 
221
- # Lval of assignment (rval is an Expression)
222
- class Assignable < NodeClass
223
- end
242
+ # lval := rval
243
+ class Assignment < Statement
244
+ def assignment?
245
+ true
246
+ end
247
+ end
224
248
 
225
- class Sql < Statement
226
- def style; 'tQ'; end
249
+ # Lval of assignment (rval is an Expression)
250
+ class Assignable < NodeClass
251
+ end
227
252
 
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 }
253
+ class Sql < Expression
254
+ def style; "tQ"; end
255
+
256
+ def sql?
257
+ true
258
+ end
259
+
260
+ def tag(prefix = nil, id = nil)
261
+ unless defined? @tag_id
262
+ if named?(:cond) and parent.for?
263
+ # This node is the conditional in a FOR loop
264
+ Tags::UnconditionalLoopTag.new(prefix, id)
265
+ else
266
+ Tags::EvaluationTag.new(prefix, id)
267
+ end.tap{|tag| @tag_id = tag.id }
268
+ end
269
+ end
236
270
  end
237
- end
238
- end
239
271
 
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
272
+ # Terminals have no children
273
+ class Terminal < NodeClass
274
+ def initialize(input, interval, elements = nil)
275
+ # Third argument nil prevents children from being assigned
276
+ super(input, interval, nil)
277
+ end
246
278
 
247
- def terminal?
248
- true
249
- end
250
- end
279
+ def terminal?
280
+ true
281
+ end
282
+ end
251
283
 
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
284
+ # This seems like it should be a Token, but it may contain TComment children
285
+ # that should be highlighted differently than the enclosing whitespace
286
+ class TWhitespace < NodeClass
287
+ def terminal?
288
+ false
289
+ end
256
290
 
257
- class TKeyword < Token
258
- def style; 'tK'; end
259
- end
291
+ def whitespace?
292
+ true
293
+ end
294
+ end
260
295
 
261
- class TIdentifier < Token
262
- def style; 'tI'; end
263
- end
296
+ class Token < Terminal
297
+ def token?
298
+ true
299
+ end
300
+ end
264
301
 
265
- class TDatatype < Token
266
- def style; 'tD'; end
267
- end
302
+ class TKeyword < Token
303
+ def style; "tK"; end
304
+
305
+ def keyword?
306
+ true
307
+ end
308
+
309
+ def tag(prefix = nil, id = nil)
310
+ unless defined? @tag_id
311
+ if named?(:cond) and parent.loop?
312
+ Tags::UnconditionalLoopTag.new(prefix, id)
313
+ else
314
+ Tags::EvaluationTag.new(prefix, id)
315
+ end
316
+ end.tap{|tag| @tag_id = tag.id }
317
+ end
318
+ end
268
319
 
269
- class TString < Token
270
- def style; 'tS'; end
271
- end
320
+ class TIdentifier < Token
321
+ def style; "tI"; end
322
+ def identifier?
323
+ true
324
+ end
325
+ end
272
326
 
273
- class TDollarQuoteMarker < Token
274
- def style; 'tM'; end
275
- end
327
+ class TDatatype < Token
328
+ def style; "tD"; end
329
+ def datatype?
330
+ true
331
+ end
332
+ end
276
333
 
277
- class TComment < Token
278
- def style; 'tC'; end
279
- end
334
+ class TString < Token
335
+ def style; "tS"; end
336
+ def string?
337
+ true
338
+ end
339
+ end
280
340
 
281
- class TLabel < Token
282
- def style; 'tL'; end
283
- end
341
+ class TDollarQuoteMarker < Token
342
+ def style; "tM"; end
343
+ end
284
344
 
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
345
+ class TComment < Token
346
+ def style; "tC"; end
347
+ def comment?
348
+ true
349
+ end
350
+ end
291
351
 
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
352
+ class TLabel < Token
353
+ def style; "tL"; end
354
+ def label?
355
+ true
356
+ end
357
+ end
303
358
 
304
- def terminal?
305
- true
306
- end
359
+ class TextNode < Terminal
360
+ end
361
+
362
+ # Stub nodes have no children, or content
363
+ class StubNode < Terminal
364
+ def stub?
365
+ true
366
+ end
367
+ end
307
368
 
308
- def stub?
309
- true
310
- end
311
- end
369
+ class NotImplemented < NodeClass
370
+ def parent=(object)
371
+ # this would go in the constructor, but parent is set from outside
372
+ raise Failure, "Grammar does not implement #{object.source_text} at line #{input.line_of(object.interval.first)}"
373
+ end
374
+ end
312
375
 
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
376
  end
318
377
  end
319
378
  end