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.
- checksums.yaml +7 -0
- data/README.md +163 -0
- data/Rakefile +29 -15
- data/bin/piggly +4 -244
- data/lib/piggly.rb +19 -17
- data/lib/piggly/command.rb +9 -0
- data/lib/piggly/command/base.rb +148 -0
- data/lib/piggly/command/report.rb +162 -0
- data/lib/piggly/command/test.rb +157 -0
- data/lib/piggly/command/trace.rb +90 -0
- data/lib/piggly/command/untrace.rb +78 -0
- data/lib/piggly/compiler.rb +7 -5
- data/lib/piggly/compiler/cache_dir.rb +119 -0
- data/lib/piggly/compiler/coverage_report.rb +63 -0
- data/lib/piggly/compiler/trace_compiler.rb +105 -0
- data/lib/piggly/config.rb +47 -22
- data/lib/piggly/dumper.rb +9 -0
- data/lib/piggly/dumper/index.rb +121 -0
- data/lib/piggly/dumper/qualified_name.rb +36 -0
- data/lib/piggly/dumper/qualified_type.rb +81 -0
- data/lib/piggly/dumper/reified_procedure.rb +142 -0
- data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
- data/lib/piggly/installer.rb +84 -42
- data/lib/piggly/parser.rb +43 -49
- data/lib/piggly/parser/grammar.tt +289 -313
- data/lib/piggly/parser/nodes.rb +270 -211
- data/lib/piggly/parser/traversal.rb +35 -33
- data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
- data/lib/piggly/profile.rb +81 -60
- data/lib/piggly/reporter.rb +5 -18
- data/lib/piggly/reporter/base.rb +103 -0
- data/lib/piggly/reporter/html_dsl.rb +63 -0
- data/lib/piggly/reporter/index.rb +108 -0
- data/lib/piggly/reporter/procedure.rb +104 -0
- data/lib/piggly/reporter/resources/highlight.js +21 -0
- data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
- data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
- data/lib/piggly/tags.rb +280 -0
- data/lib/piggly/task.rb +191 -40
- data/lib/piggly/util.rb +8 -27
- data/lib/piggly/util/blankslate.rb +114 -0
- data/lib/piggly/util/cacheable.rb +19 -0
- data/lib/piggly/util/enumerable.rb +44 -0
- data/lib/piggly/util/file.rb +17 -0
- data/lib/piggly/util/process_queue.rb +96 -0
- data/lib/piggly/util/thunk.rb +39 -0
- data/lib/piggly/version.rb +8 -8
- data/spec/examples/compiler/cacheable_spec.rb +190 -0
- data/spec/examples/compiler/report_spec.rb +25 -0
- data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
- data/spec/examples/config_spec.rb +61 -0
- data/spec/examples/dumper/index_spec.rb +197 -0
- data/spec/examples/dumper/procedure_spec.rb +116 -0
- data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
- data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
- data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
- data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
- data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
- data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
- data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
- data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
- data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
- data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
- data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
- data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
- data/spec/examples/installer_spec.rb +59 -0
- data/spec/examples/parser/nodes_spec.rb +73 -0
- data/spec/examples/parser/traversal_spec.rb +14 -0
- data/spec/examples/parser_spec.rb +115 -0
- data/spec/examples/profile_spec.rb +153 -0
- data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
- data/spec/examples/reporter/html/index_spec.rb +0 -0
- data/spec/examples/reporter/html_spec.rb +1 -0
- data/spec/examples/reporter_spec.rb +0 -0
- data/spec/{compiler → examples}/tags_spec.rb +10 -10
- data/spec/examples/task_spec.rb +0 -0
- data/spec/examples/util/cacheable_spec.rb +41 -0
- data/spec/examples/util/enumerable_spec.rb +64 -0
- data/spec/examples/util/file_spec.rb +40 -0
- data/spec/examples/util/process_queue_spec.rb +16 -0
- data/spec/examples/util/thunk_spec.rb +58 -0
- data/spec/examples/version_spec.rb +0 -0
- data/spec/issues/007_spec.rb +25 -0
- data/spec/issues/008_spec.rb +73 -0
- data/spec/issues/018_spec.rb +25 -0
- data/spec/spec_helper.rb +253 -9
- metadata +136 -93
- data/README.markdown +0 -116
- data/lib/piggly/compiler/cache.rb +0 -151
- data/lib/piggly/compiler/pretty.rb +0 -67
- data/lib/piggly/compiler/queue.rb +0 -46
- data/lib/piggly/compiler/tags.rb +0 -244
- data/lib/piggly/compiler/trace.rb +0 -91
- data/lib/piggly/filecache.rb +0 -40
- data/lib/piggly/parser/parser.rb +0 -11794
- data/lib/piggly/reporter/html.rb +0 -207
- data/spec/compiler/cache_spec.rb +0 -9
- data/spec/compiler/pretty_spec.rb +0 -9
- data/spec/compiler/queue_spec.rb +0 -3
- data/spec/compiler/rewrite_spec.rb +0 -3
- data/spec/config_spec.rb +0 -58
- data/spec/filecache_spec.rb +0 -70
- data/spec/fixtures/snippets.sql +0 -158
- data/spec/grammar/tokens/lval_spec.rb +0 -50
- data/spec/parser_spec.rb +0 -8
- data/spec/profile_spec.rb +0 -5
@@ -1,67 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w(.. reporter))
|
2
|
-
|
3
|
-
module Piggly
|
4
|
-
|
5
|
-
#
|
6
|
-
# Produces HTML output to report coverage of tagged nodes in the tree
|
7
|
-
#
|
8
|
-
class PrettyCompiler
|
9
|
-
include Piggly::HtmlTag
|
10
|
-
|
11
|
-
def self.compile(path, profile)
|
12
|
-
new(profile).send(:compile, path)
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(profile)
|
16
|
-
@profile = profile
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def compile(path)
|
22
|
-
lines = File.read(path).count("\n") + 1
|
23
|
-
|
24
|
-
# recompile (should be cache hit) to identify tagged nodes
|
25
|
-
data = TraceCompiler.cache(path)
|
26
|
-
html = traverse(data['tree'])
|
27
|
-
|
28
|
-
return 'html' => html,
|
29
|
-
'lines' => 1..lines,
|
30
|
-
'tags' => data['tags']
|
31
|
-
end
|
32
|
-
|
33
|
-
def traverse(node, string='')
|
34
|
-
if node.terminal?
|
35
|
-
# terminals (leaves) are never tagged
|
36
|
-
if node.style
|
37
|
-
string << '<span class="' << node.style << '">' << e(node.text_value) << '</span>'
|
38
|
-
else
|
39
|
-
string << e(node.text_value)
|
40
|
-
end
|
41
|
-
else
|
42
|
-
# non-terminals never write their text_value
|
43
|
-
node.elements.each do |child|
|
44
|
-
if child.tagged?
|
45
|
-
|
46
|
-
# retreive the profiled tag
|
47
|
-
tag = @profile.by_id[child.tag_id]
|
48
|
-
|
49
|
-
if tag.complete?
|
50
|
-
string << '<span class="' << tag.style << '" id="T' << tag.id << '">'
|
51
|
-
else
|
52
|
-
string << '<span class="' << tag.style << '" id="T' << tag.id << '" title="' << tag.description << '">'
|
53
|
-
end
|
54
|
-
|
55
|
-
traverse(child, string)
|
56
|
-
string << '</span>'
|
57
|
-
else
|
58
|
-
traverse(child, string)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
string
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module Piggly
|
2
|
-
|
3
|
-
#
|
4
|
-
# Executes blocks in parallel subprocesses
|
5
|
-
#
|
6
|
-
class Queue
|
7
|
-
|
8
|
-
def self.children=(value)
|
9
|
-
@children = value
|
10
|
-
end
|
11
|
-
|
12
|
-
# add a compile job to the queue
|
13
|
-
def self.queue(&block)
|
14
|
-
(@queue ||= []) << block
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.child
|
18
|
-
queue { yield }
|
19
|
-
end
|
20
|
-
|
21
|
-
# start scheduler thread
|
22
|
-
def self.start
|
23
|
-
@active = 0
|
24
|
-
@children ||= 1
|
25
|
-
@queue ||= []
|
26
|
-
|
27
|
-
while block = @queue.shift
|
28
|
-
if @active >= @children
|
29
|
-
pid = Process.wait
|
30
|
-
@active -= 1
|
31
|
-
end
|
32
|
-
|
33
|
-
# enable enterprise ruby feature
|
34
|
-
GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
|
35
|
-
|
36
|
-
# use exit! to avoid auto-running any test suites
|
37
|
-
pid = Process.fork{ block.call; exit! 0 }
|
38
|
-
|
39
|
-
@active += 1
|
40
|
-
end
|
41
|
-
|
42
|
-
Process.waitall
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
data/lib/piggly/compiler/tags.rb
DELETED
@@ -1,244 +0,0 @@
|
|
1
|
-
module Piggly
|
2
|
-
|
3
|
-
#
|
4
|
-
# Coverage is tracked by attaching these compiler-generated tags to various nodes in a stored
|
5
|
-
# procedure's parse tree. These tags each have a unique string identifier which is printed by
|
6
|
-
# various parts of the recompiled stored procedure, and the output is then recognized by
|
7
|
-
# Profile.notice_processor, which calls #ping on the tag corresponding to the printed string.
|
8
|
-
#
|
9
|
-
# After test execution is complete, each AST is walked and Tag values attached to NodeClass
|
10
|
-
# values are used to produce the coverage report
|
11
|
-
#
|
12
|
-
class Tag
|
13
|
-
PATTERN = /[0-9a-f]{16}/
|
14
|
-
|
15
|
-
attr_accessor :id
|
16
|
-
|
17
|
-
def initialize(prefix = nil, id = nil)
|
18
|
-
@id = Digest::MD5.hexdigest(prefix.to_s + (id || object_id).to_s).slice(0, 16)
|
19
|
-
end
|
20
|
-
|
21
|
-
alias to_s id
|
22
|
-
|
23
|
-
# Defined here in case ActiveSupport hasn't defined it on Object
|
24
|
-
def tap
|
25
|
-
yield self
|
26
|
-
self
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class EvaluationTag < Tag
|
31
|
-
def initialize(*args)
|
32
|
-
clear
|
33
|
-
super
|
34
|
-
end
|
35
|
-
|
36
|
-
def type
|
37
|
-
:block
|
38
|
-
end
|
39
|
-
|
40
|
-
def ping(value)
|
41
|
-
@ran = true
|
42
|
-
end
|
43
|
-
|
44
|
-
def style
|
45
|
-
"c#{@ran ? '1' : '0'}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_f
|
49
|
-
@ran ? 100.0 : 0.0
|
50
|
-
end
|
51
|
-
|
52
|
-
def complete?
|
53
|
-
@ran
|
54
|
-
end
|
55
|
-
|
56
|
-
def description
|
57
|
-
@ran ? 'full coverage' : 'never evaluated'
|
58
|
-
end
|
59
|
-
|
60
|
-
# Resets code coverage
|
61
|
-
def clear
|
62
|
-
@ran = false
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
#
|
67
|
-
# Sequence of statements
|
68
|
-
#
|
69
|
-
class BlockTag < EvaluationTag
|
70
|
-
end
|
71
|
-
|
72
|
-
#
|
73
|
-
# Procedure calls, raise exception, exits, returns
|
74
|
-
#
|
75
|
-
class UnconditionalBranchTag < EvaluationTag
|
76
|
-
# aggregate this coverage data with conditional branches
|
77
|
-
def type
|
78
|
-
:branch
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
class LoopConditionTag < Tag
|
83
|
-
STATES = { # never terminates normally (so @pass must be false)
|
84
|
-
0b0000 => 'condition was never evaluated',
|
85
|
-
0b0001 => 'condition never evaluates false (terminates early). loop always iterates more than once',
|
86
|
-
0b0010 => 'condition never evaluates false (terminates early). loop always iterates only once',
|
87
|
-
0b0011 => 'condition never evaluates false (terminates early)',
|
88
|
-
# terminates normally (one of @pass, @once, @twice must be true)
|
89
|
-
0b1001 => 'loop always iterates more than once',
|
90
|
-
0b1010 => 'loop always iterates only once',
|
91
|
-
0b1011 => 'loop never passes through',
|
92
|
-
0b1100 => 'loop always passes through',
|
93
|
-
0b1101 => 'loop never iterates only once',
|
94
|
-
0b1110 => 'loop never iterates more than once',
|
95
|
-
0b1111 => 'full coverage' }
|
96
|
-
|
97
|
-
attr_reader :pass, :once, :twice, :ends, :count
|
98
|
-
|
99
|
-
def initialize(*args)
|
100
|
-
clear
|
101
|
-
super
|
102
|
-
end
|
103
|
-
|
104
|
-
def type
|
105
|
-
:loop
|
106
|
-
end
|
107
|
-
|
108
|
-
def ping(value)
|
109
|
-
case value
|
110
|
-
when 't'
|
111
|
-
# loop iterated
|
112
|
-
@count += 1
|
113
|
-
else
|
114
|
-
# loop terminated
|
115
|
-
case @count
|
116
|
-
when 0; @pass = true
|
117
|
-
when 1; @once = true
|
118
|
-
else; @twice = true
|
119
|
-
end
|
120
|
-
@count = 0
|
121
|
-
|
122
|
-
# this isn't accurate. there needs to be a signal at the end
|
123
|
-
# of the loop body to indicate it was reached. otherwise its
|
124
|
-
# possible each iteration restarts early with 'continue'
|
125
|
-
@ends = true
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def style
|
130
|
-
"l#{[@pass, @once, @twice, @ends].map{|b| b ? 1 : 0}}"
|
131
|
-
end
|
132
|
-
|
133
|
-
def to_f
|
134
|
-
# value space:
|
135
|
-
# (1,2,X) - loop iterated at least twice and terminated normally
|
136
|
-
# (1,X) - loop iterated only once and terminated normally
|
137
|
-
# (0,X) - loop never iterated and terminated normally (pass-thru)
|
138
|
-
# () - loop condition was never executed
|
139
|
-
#
|
140
|
-
# these combinations are ignored, because adding tests for them will probably not reveal bugs
|
141
|
-
# (1,2) - loop iterated at least twice but terminated early
|
142
|
-
# (1) - loop iterated only once but terminated early
|
143
|
-
100 * ([@pass, @once, @twice, @ends].count{|x| x } / 4.0)
|
144
|
-
end
|
145
|
-
|
146
|
-
def complete?
|
147
|
-
@pass and @once and @twice and @ends
|
148
|
-
end
|
149
|
-
|
150
|
-
def description
|
151
|
-
# weird hack so ForCollectionTag uses its separate constant
|
152
|
-
self.class::STATES.fetch(n = state, "unknown tag state: #{n}")
|
153
|
-
end
|
154
|
-
|
155
|
-
# Returns state represented as a 4-bit integer
|
156
|
-
def state
|
157
|
-
[@ends,@pass,@once,@twice].reverse.inject([0,0]){|(k,n), bit| [k + 1, n | (bit ? 1 : 0) << k] }.last
|
158
|
-
end
|
159
|
-
|
160
|
-
def clear
|
161
|
-
@pass = false
|
162
|
-
@once = false
|
163
|
-
@twice = false
|
164
|
-
@ends = false
|
165
|
-
@count = 0
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
class ForCollectionTag < LoopConditionTag
|
170
|
-
STATES = LoopConditionTag::STATES.merge \
|
171
|
-
0b0001 => 'loop always iterates more than once and always terminates early.',
|
172
|
-
0b0010 => 'loop always iterates only once and always terminates early.',
|
173
|
-
0b0011 => 'loop always terminates early',
|
174
|
-
0b0100 => 'loop always passes through'
|
175
|
-
|
176
|
-
def ping(value)
|
177
|
-
case value
|
178
|
-
when 't'
|
179
|
-
# start of iteration
|
180
|
-
@count += 1
|
181
|
-
when '@'
|
182
|
-
# end of iteration
|
183
|
-
@ends = true
|
184
|
-
when 'f'
|
185
|
-
# loop exit
|
186
|
-
case @count
|
187
|
-
when 0; @pass = true
|
188
|
-
when 1; @once = true
|
189
|
-
else; @twice = true
|
190
|
-
end
|
191
|
-
@count = 0
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
class BranchConditionTag < Tag
|
197
|
-
attr_reader :true, :false
|
198
|
-
|
199
|
-
def initialize(*args)
|
200
|
-
clear
|
201
|
-
super
|
202
|
-
end
|
203
|
-
|
204
|
-
def type
|
205
|
-
:branch
|
206
|
-
end
|
207
|
-
|
208
|
-
def ping(value)
|
209
|
-
case value
|
210
|
-
when 't'; @true = true
|
211
|
-
when 'f'; @false = true
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
def style
|
216
|
-
"b#{@true ? 1 : 0}#{@false ? 1 : 0 }"
|
217
|
-
end
|
218
|
-
|
219
|
-
def to_f
|
220
|
-
(@true and @false) ? 100.0 : (@true or @false) ? 50.0 : 0.0
|
221
|
-
end
|
222
|
-
|
223
|
-
def complete?
|
224
|
-
@true and @false
|
225
|
-
end
|
226
|
-
|
227
|
-
def description
|
228
|
-
if @true and @false
|
229
|
-
'full coverage'
|
230
|
-
elsif @true
|
231
|
-
'never evaluates false'
|
232
|
-
elsif @false
|
233
|
-
'never evaluates true'
|
234
|
-
else
|
235
|
-
'never evaluated'
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
def clear
|
240
|
-
@true, @false = false
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
module Piggly
|
2
|
-
|
3
|
-
#
|
4
|
-
# Walks the parse tree, attaching Tag values and rewriting source code to ping them.
|
5
|
-
#
|
6
|
-
class TraceCompiler
|
7
|
-
include FileCache
|
8
|
-
include CompilerCache
|
9
|
-
|
10
|
-
attr_accessor :nodes
|
11
|
-
|
12
|
-
def self.compile(tree, args)
|
13
|
-
new(args.fetch(:path)).send(:compile, tree)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.compiler_path
|
17
|
-
__FILE__
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(path)
|
21
|
-
# create unique prefix for each file, prepended to each node's tag
|
22
|
-
@prefix = File.expand_path(path)
|
23
|
-
@tags = []
|
24
|
-
end
|
25
|
-
|
26
|
-
#
|
27
|
-
# Destructively modifies +tree+ (by attaching tags) and returns the tree
|
28
|
-
# along with the modified source code, and the list of tags. The tag list
|
29
|
-
# is passed along to Profile to compute coverage information. The tree is
|
30
|
-
# passed to PrettyCompiler
|
31
|
-
#
|
32
|
-
def compile(tree)
|
33
|
-
puts "Compiling #{@prefix}"
|
34
|
-
return 'code.sql' => traverse(tree),
|
35
|
-
'tree' => tree,
|
36
|
-
'tags' => @tags,
|
37
|
-
'prefix' => @prefix
|
38
|
-
end
|
39
|
-
|
40
|
-
def traverse(node)
|
41
|
-
if node.terminal? or node.expression?
|
42
|
-
node.source_text
|
43
|
-
else
|
44
|
-
if node.respond_to?(:condStub) and node.respond_to?(:cond)
|
45
|
-
# preserve opening parenthesis and whitespace before injecting code. this way
|
46
|
-
# IF(test) becomes IF(piggly_cond(TAG, test)) instead of IFpiggly_cond(TAG, (test))
|
47
|
-
pre, cond = node.cond.expr.text_value.match(/\A(\(?[\t\n\r ]*)(.+)\z/m).captures
|
48
|
-
node.cond.source_text = ""
|
49
|
-
|
50
|
-
@tags << node.cond.tag(@prefix)
|
51
|
-
|
52
|
-
node.condStub.source_text = "#{pre}piggly_cond($PIGGLY$#{node.cond.tag_id}$PIGGLY$, #{cond})"
|
53
|
-
node.condStub.source_text << traverse(node.cond.tail) # preserve trailing whitespace
|
54
|
-
end
|
55
|
-
|
56
|
-
if node.respond_to?(:bodyStub)
|
57
|
-
if node.respond_to?(:exitStub) and node.respond_to?(:cond)
|
58
|
-
@tags << node.body.tag(@prefix)
|
59
|
-
@tags << node.cond.tag(@prefix)
|
60
|
-
|
61
|
-
# a hack to simulate a loop conditional statement in ForLoop. signal condition was true
|
62
|
-
# when body is executed. when exit stub is reached, signal condition was false
|
63
|
-
node.bodyStub.source_text = "perform piggly_cond($PIGGLY$#{node.cond.tag_id}$PIGGLY$, true);#{node.indent(:bodySpace)}"
|
64
|
-
node.bodyStub.source_text << "perform piggly_branch($PIGGLY$#{node.body.tag_id}$PIGGLY$);#{node.indent(:bodySpace)}"
|
65
|
-
|
66
|
-
if node.respond_to?(:doneStub)
|
67
|
-
# signal the end of an iteration was reached
|
68
|
-
node.doneStub.source_text = "#{node.indent(:bodySpace)}perform piggly_signal($PIGGLY$#{node.cond.tag_id}$PIGGLY$, $PIGGLY$@$PIGGLY$);"
|
69
|
-
node.doneStub.source_text << node.body.indent
|
70
|
-
end
|
71
|
-
|
72
|
-
# signal the loop terminated
|
73
|
-
node.exitStub.source_text = "\n#{node.indent}perform piggly_cond($PIGGLY$#{node.cond.tag_id}$PIGGLY$, false);"
|
74
|
-
elsif node.respond_to?(:body)
|
75
|
-
# no condition:
|
76
|
-
# BEGIN ... END;
|
77
|
-
# LOOP ... END;
|
78
|
-
# ... ELSE ... END;
|
79
|
-
# CONTINUE label;
|
80
|
-
# EXIT label;
|
81
|
-
@tags << node.body.tag(@prefix)
|
82
|
-
node.bodyStub.source_text = "perform piggly_branch($PIGGLY$#{node.body.tag_id}$PIGGLY$);#{node.indent(:bodySpace)}"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# traverse children (in which we just injected code)
|
87
|
-
node.elements.map{|e| traverse(e) }.join
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|