bud 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/budplot +37 -12
- data/bin/budtimelines +20 -22
- data/bin/budvis +1 -1
- data/docs/cheat.md +54 -17
- data/docs/operational.md +1 -1
- data/lib/bud.rb +31 -18
- data/lib/bud/bud_meta.rb +7 -7
- data/lib/bud/bust/bust.rb +2 -2
- data/lib/bud/collections.rb +80 -68
- data/lib/bud/deploy/ec2deploy.rb +1 -1
- data/lib/bud/graphs.rb +9 -11
- data/lib/bud/joins.rb +29 -20
- data/lib/bud/monkeypatch.rb +8 -2
- data/lib/bud/rebl.rb +29 -13
- data/lib/bud/rewrite.rb +40 -39
- data/lib/bud/server.rb +1 -1
- data/lib/bud/state.rb +3 -3
- data/lib/bud/storage/dbm.rb +4 -4
- data/lib/bud/storage/tokyocabinet.rb +4 -4
- data/lib/bud/storage/zookeeper.rb +3 -3
- data/lib/bud/stratify.rb +6 -3
- data/lib/bud/viz.rb +1 -1
- data/lib/bud/viz_util.rb +11 -7
- metadata +10 -8
data/lib/bud/graphs.rb
CHANGED
@@ -5,7 +5,7 @@ require 'graphviz'
|
|
5
5
|
class GraphGen #:nodoc: all
|
6
6
|
attr_reader :nodes
|
7
7
|
|
8
|
-
def initialize(tableinfo, cycle, name, budtime, collapse=false, cardinalities={})
|
8
|
+
def initialize(tableinfo, builtin_tables, cycle, name, budtime, collapse=false, cardinalities={})
|
9
9
|
@graph = GraphViz.new(:G, :type => :digraph, :label => "")
|
10
10
|
@graph.node[:fontname] = "Times-Roman"
|
11
11
|
@graph.node[:fontsize] = 18
|
@@ -15,9 +15,9 @@ class GraphGen #:nodoc: all
|
|
15
15
|
@name = name
|
16
16
|
@collapse = collapse
|
17
17
|
@budtime = budtime
|
18
|
-
@
|
18
|
+
@builtin_tables = builtin_tables
|
19
19
|
|
20
|
-
# map: table -> type
|
20
|
+
# map: table name -> type
|
21
21
|
@tabinf = {}
|
22
22
|
tableinfo.each do |ti|
|
23
23
|
@tabinf[ti[0].to_s] = ti[1]
|
@@ -75,8 +75,7 @@ class GraphGen #:nodoc: all
|
|
75
75
|
head = d[1]
|
76
76
|
body = d[3]
|
77
77
|
|
78
|
-
|
79
|
-
if @internals[head] or @internals[body]
|
78
|
+
if @builtin_tables.has_key?(head.to_sym) or @builtin_tables.has_key?(body.to_sym)
|
80
79
|
next
|
81
80
|
end
|
82
81
|
|
@@ -182,11 +181,11 @@ class GraphGen #:nodoc: all
|
|
182
181
|
@nodes["T"].penwidth = 3
|
183
182
|
|
184
183
|
@tabinf.each_pair do |k, v|
|
185
|
-
unless @nodes[name_of(k
|
186
|
-
addonce(k
|
184
|
+
unless @nodes[name_of(k)] or @builtin_tables[k.to_sym]
|
185
|
+
addonce(k, false)
|
187
186
|
end
|
188
187
|
if v == "Bud::BudPeriodic"
|
189
|
-
addedge("S", k
|
188
|
+
addedge("S", k, false, false, false)
|
190
189
|
end
|
191
190
|
end
|
192
191
|
|
@@ -263,7 +262,7 @@ class SpaceTime
|
|
263
262
|
|
264
263
|
squeues = {}
|
265
264
|
queues.each_pair do |k, v|
|
266
|
-
squeues[k] = v.sort{|a, b| a <=> b}
|
265
|
+
squeues[k] = v.sort{|a, b| a.to_i <=> b.to_i}
|
267
266
|
end
|
268
267
|
|
269
268
|
# create the nodes and the timeline edges first.
|
@@ -271,8 +270,7 @@ class SpaceTime
|
|
271
270
|
v.each_with_index do |item, i|
|
272
271
|
label = "#{k}-#{item}"
|
273
272
|
if @links
|
274
|
-
url = "DBM_#{k}
|
275
|
-
#puts "URL is #{url}"
|
273
|
+
url = "DBM_#{k}/tm_#{item}.svg"
|
276
274
|
end
|
277
275
|
snd = @subs[k].add_node(label, {:label => item.to_s, :width => 0.1, :height => 0.1, :fontsize => 6, :pos => [1, i], :group => k, :URL => url})
|
278
276
|
|
data/lib/bud/joins.rb
CHANGED
@@ -30,11 +30,11 @@ module Bud
|
|
30
30
|
memo[r.tabname] += 1
|
31
31
|
memo
|
32
32
|
end
|
33
|
-
counts.each do |name, cnt|
|
33
|
+
counts.each do |name, cnt|
|
34
34
|
raise Bud::CompileError, "#{cnt} instances of #{name} in rule; only one self-join currently allowed per rule" if cnt > 2
|
35
35
|
@selfjoins << name if cnt == 2
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
|
39
39
|
# recurse to form a tree of binary BudJoins
|
40
40
|
@rels = [rellist[0]]
|
@@ -75,7 +75,7 @@ module Bud
|
|
75
75
|
preds = []
|
76
76
|
rels.each do |r|
|
77
77
|
rels.each do |s|
|
78
|
-
matches = r.
|
78
|
+
matches = r.cols & s.cols
|
79
79
|
matches.each do |c|
|
80
80
|
preds << [bud_instance.send(r.tabname).send(c), bud_instance.send(s.tabname).send(c)] unless r.tabname.to_s >= s.tabname.to_s
|
81
81
|
end
|
@@ -90,7 +90,7 @@ module Bud
|
|
90
90
|
public
|
91
91
|
def flatten(*preds)
|
92
92
|
setup_preds(preds)
|
93
|
-
flat_schema = @rels.map{|r| r.
|
93
|
+
flat_schema = @rels.map{|r| r.cols}.flatten(1)
|
94
94
|
dupfree_schema = []
|
95
95
|
# while loop here (inefficiently) ensures no collisions
|
96
96
|
while dupfree_schema == [] or dupfree_schema.uniq.length < dupfree_schema.length
|
@@ -121,7 +121,8 @@ module Bud
|
|
121
121
|
# map each (nested) item in the collection into a string, suitable for placement in stdio
|
122
122
|
def inspected
|
123
123
|
raise BudError, "join left unconverted to binary" if @rels.length > 2
|
124
|
-
|
124
|
+
tabnames = @origrels.map {|r| r.tabname.to_s}.join " * "
|
125
|
+
[["(#{tabnames}): [#{self.map{|r1, r2| "\n (#{r1.inspect}, #{r2.inspect})"}}]"]]
|
125
126
|
end
|
126
127
|
|
127
128
|
public
|
@@ -168,7 +169,7 @@ module Bud
|
|
168
169
|
end
|
169
170
|
|
170
171
|
alias combos pairs
|
171
|
-
|
172
|
+
|
172
173
|
# the natural join: given a * expression over n collections, form all
|
173
174
|
# combinations of items that have the same values in matching fields
|
174
175
|
public
|
@@ -209,23 +210,32 @@ module Bud
|
|
209
210
|
self.extend(Bud::BudOuterJoin)
|
210
211
|
blk.nil? ? self : map(&blk)
|
211
212
|
end
|
212
|
-
|
213
|
+
|
213
214
|
# AntiJoin
|
214
215
|
# note: unlike other join methods (e.g. lefts) all we do with the return value
|
215
216
|
# of block is check whether it's nil. Putting "projection" logic in the block
|
216
217
|
# has no effect on the output.
|
217
218
|
public
|
218
219
|
def anti(*preds, &blk)
|
220
|
+
return [] unless @bud_instance.stratum_first_iter
|
219
221
|
@origpreds = preds
|
220
222
|
# no projection involved here, so we can propagate the schema
|
221
|
-
@
|
223
|
+
@cols = @rels[0].cols
|
222
224
|
setup_preds(preds)
|
223
225
|
setup_state if self.class <= Bud::BudJoin
|
224
|
-
if
|
225
|
-
@matches = map { |r, s|
|
226
|
-
@rels[0].map {|r| (@matches.include? r) ? nil : r}.compact
|
226
|
+
if blk.nil?
|
227
|
+
@matches = map { |r, s| r }
|
227
228
|
else
|
228
|
-
|
229
|
+
@matches = map { |r, s| r unless blk.call(r, s).nil? }.compact
|
230
|
+
end
|
231
|
+
# XXX: @matches is an Array, which makes include? O(n)
|
232
|
+
@rels[0].map {|r| (@matches.include? r) ? nil : r}
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
def check_join_pred(pred, join_rels)
|
237
|
+
unless join_rels.include? pred[0]
|
238
|
+
raise Bud::CompileError, "illegal predicate: collection #{pred[0]} is not being joined"
|
229
239
|
end
|
230
240
|
end
|
231
241
|
|
@@ -239,21 +249,20 @@ module Bud
|
|
239
249
|
unless @rels[1].class <= Bud::BudJoin
|
240
250
|
tabnames = @rels.map{ |r| r.tabname }
|
241
251
|
allpreds.each do |p|
|
242
|
-
|
243
|
-
|
244
|
-
end
|
252
|
+
check_join_pred(p[0], tabnames)
|
253
|
+
check_join_pred(p[1], tabnames)
|
245
254
|
end
|
246
255
|
end
|
247
256
|
@hashpreds = allpreds.reject {|p| p[0][0] != @rels[0].tabname}
|
248
257
|
@localpreds = @hashpreds
|
249
|
-
|
258
|
+
|
250
259
|
# only allow preds on the same table name if they're on a self-joined table
|
251
|
-
@localpreds.each do |p|
|
260
|
+
@localpreds.each do |p|
|
252
261
|
if p[0][0] == p[1][0] and not @selfjoins.include? p[0][0]
|
253
|
-
raise Bud::CompileError, "single-table predicate on #{p[0][0]} disallowed in joins"
|
262
|
+
raise Bud::CompileError, "single-table predicate on #{p[0][0]} disallowed in joins"
|
254
263
|
end
|
255
264
|
end
|
256
|
-
|
265
|
+
|
257
266
|
@localpreds += allpreds.map do |p|
|
258
267
|
p if p[0][0] == p[1][0] and (p[0][0] == @rels[0].tabname or p[0][0] == @rels[1].tabname)
|
259
268
|
end.compact
|
@@ -385,7 +394,7 @@ module Bud
|
|
385
394
|
name, offset = entry[0], entry[1]
|
386
395
|
|
387
396
|
# determine which subtuple of the collection contains the table
|
388
|
-
# referenced in entry.
|
397
|
+
# referenced in entry.
|
389
398
|
subtuple = 0
|
390
399
|
origrels[1..origrels.length].each_with_index do |t,i|
|
391
400
|
if t.tabname == entry[0]
|
data/lib/bud/monkeypatch.rb
CHANGED
@@ -6,6 +6,12 @@ class Module
|
|
6
6
|
mod, local_name = spec.first
|
7
7
|
raise Bud::CompileError unless (mod.class <= Module and local_name.class <= Symbol)
|
8
8
|
|
9
|
+
# Attempting to import a module that has already included the Bud module
|
10
|
+
# results in problems (and is a bad idea anyway), so disallow it.
|
11
|
+
if mod.included_modules.include? Bud
|
12
|
+
raise Bud::CompileError, "cannot import #{mod} because it has already included Bud"
|
13
|
+
end
|
14
|
+
|
9
15
|
# To correctly expand qualified references to an imported module, we keep a
|
10
16
|
# table with the local bind names of all the modules imported by this
|
11
17
|
# module. To handle nested references (a.b.c.d etc.), the import table for
|
@@ -41,7 +47,7 @@ class Module
|
|
41
47
|
@block_id += 1
|
42
48
|
else
|
43
49
|
unless block_name.class <= Symbol
|
44
|
-
raise Bud::CompileError, "
|
50
|
+
raise Bud::CompileError, "bloom block names must be a symbol: #{block_name}"
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
@@ -53,7 +59,7 @@ class Module
|
|
53
59
|
# Don't allow duplicate named bloom blocks to be defined within a single
|
54
60
|
# module; this indicates a likely programmer error.
|
55
61
|
if instance_methods(false).include? meth_name
|
56
|
-
raise Bud::CompileError, "
|
62
|
+
raise Bud::CompileError, "duplicate named bloom block: '#{block_name}' in #{self}"
|
57
63
|
end
|
58
64
|
define_method(meth_name.to_sym, &block)
|
59
65
|
end
|
data/lib/bud/rebl.rb
CHANGED
@@ -23,32 +23,32 @@ class ReblShell
|
|
23
23
|
@@escape_char = '/'
|
24
24
|
@@commands =
|
25
25
|
{"tick" => [lambda {|lib,argv| lib.tick([Integer(argv[1]), 1].max)},
|
26
|
-
"tick [x]
|
26
|
+
"tick [x]\texecutes x (or 1) timesteps"],
|
27
27
|
|
28
28
|
"run" => [lambda {|lib,_| lib.run},
|
29
|
-
"run
|
29
|
+
"run\ttick until quiescence, a breakpoint, or #{@@escape_char}stop"],
|
30
30
|
|
31
31
|
"stop" => [lambda {|lib,_| lib.stop},
|
32
|
-
"stop
|
32
|
+
"stop\tstop ticking"],
|
33
33
|
|
34
34
|
"lsrules" => [lambda {|lib,_| lib.rules.sort{|a,b| a[0] <=> b[0]}.each {|k,v| puts "#{k}: "+v}},
|
35
|
-
"lsrules
|
35
|
+
"lsrules\tlist rules"],
|
36
36
|
|
37
37
|
"rmrule" => [lambda {|lib,argv| lib.del_rule(Integer(argv[1]))},
|
38
|
-
"rmrule x
|
38
|
+
"rmrule x\tremove rule number x"],
|
39
39
|
|
40
40
|
"lscollections" => [lambda {|lib,_| lib.state.sort{|a,b| a[0] <=> b[0]}.each {|k,v| puts "#{k}: "+v}},
|
41
|
-
"lscollections
|
41
|
+
"lscollections\tlist collections"],
|
42
42
|
|
43
43
|
"dump" => [lambda {|lib,argv| lib.dump(argv[1])},
|
44
|
-
"dump c
|
44
|
+
"dump c\tdump contents of collection c"],
|
45
45
|
|
46
|
-
"exit" => [lambda {|_,_| do_exit}, "exit
|
46
|
+
"exit" => [lambda {|_,_| do_exit}, "exit\texit rebl"],
|
47
47
|
|
48
|
-
"quit" => [lambda {|_,_| do_exit}, "quit
|
48
|
+
"quit" => [lambda {|_,_| do_exit}, "quit\texit rebl"],
|
49
49
|
|
50
50
|
"help" => [lambda {|_,_| pretty_help},
|
51
|
-
"help
|
51
|
+
"help\tprint this help message"]}
|
52
52
|
@@abbrevs = @@commands.keys.abbrev
|
53
53
|
@@exit_message = "Rebellion quashed."
|
54
54
|
|
@@ -151,7 +151,7 @@ class ReblShell
|
|
151
151
|
cmd_list.each do |c|
|
152
152
|
v = @@commands[c]
|
153
153
|
puts @@escape_char +
|
154
|
-
v[1].gsub(/\t/, " "*(maxlen +
|
154
|
+
v[1].gsub(/\t/, " "*(maxlen + 4 - v[1].split("\t")[0].size))
|
155
155
|
end
|
156
156
|
puts "\nbreakpoints:"
|
157
157
|
puts "a breakpoint is a rule with the 'breakpoint' scratch on the left of "+
|
@@ -228,8 +228,20 @@ class LibRebl
|
|
228
228
|
|
229
229
|
# Dumps the contents of a table at the current time.
|
230
230
|
def dump(c)
|
231
|
-
|
232
|
-
|
231
|
+
if c.nil?
|
232
|
+
puts "Error: dump must be passed a collection name"
|
233
|
+
elsif not @rebl_class_inst.tables.has_key? c.to_sym
|
234
|
+
puts "Error: non-existent collection \"#{c}\""
|
235
|
+
else
|
236
|
+
tups = @rebl_class_inst.tables[c.to_sym].to_a.sort
|
237
|
+
if tups.empty?
|
238
|
+
puts "(empty)"
|
239
|
+
else
|
240
|
+
tups.each do |t|
|
241
|
+
puts t.inspect
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
233
245
|
end
|
234
246
|
|
235
247
|
# Declares a new collection.
|
@@ -246,6 +258,10 @@ class LibRebl
|
|
246
258
|
# Deactivates a rule at the current time; any tuples derived by the rule at
|
247
259
|
# a previous time are still available.
|
248
260
|
def del_rule(rid)
|
261
|
+
unless @rules.has_key? rid
|
262
|
+
puts "No rule with ID #{rid}"
|
263
|
+
return
|
264
|
+
end
|
249
265
|
@rules.delete(rid)
|
250
266
|
reinstantiate
|
251
267
|
end
|
data/lib/bud/rewrite.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'ruby2ruby'
|
3
2
|
|
4
3
|
class RuleRewriter < Ruby2Ruby # :nodoc: all
|
5
4
|
attr_accessor :rule_indx, :rules, :depends
|
@@ -11,7 +10,8 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
11
10
|
:== => 1, :+ => 1, :<= => 1, :- => 1, :< => 1, :> => 1,
|
12
11
|
:* => 1, :pairs => 1, :matches => 1, :combos => 1, :flatten => 1,
|
13
12
|
:lefts => 1, :rights => 1, :map => 1, :flat_map => 1, :pro => 1,
|
14
|
-
:schema => 1, :keys => 1, :values => 1, :
|
13
|
+
:schema => 1, :keys => 1, :values => 1, :cols => 1, :key_cols => 1,
|
14
|
+
:val_cols => 1, :payloads => 1, :~ => 1
|
15
15
|
}
|
16
16
|
@temp_ops = {:-@ => 1, :~ => 1, :+@ => 1}
|
17
17
|
@tables = {}
|
@@ -25,10 +25,8 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
25
25
|
|
26
26
|
def call_is_attr_deref?(recv, op)
|
27
27
|
if recv.first == :call and @bud_instance.tables.has_key? recv[2]
|
28
|
-
|
29
|
-
if
|
30
|
-
return true
|
31
|
-
end
|
28
|
+
cols = @bud_instance.tables[recv[2]].cols
|
29
|
+
return true if cols and cols.include? op
|
32
30
|
end
|
33
31
|
return false
|
34
32
|
end
|
@@ -157,7 +155,7 @@ class AttrNameRewriter < SexpProcessor # :nodoc: all
|
|
157
155
|
elsif exp[2] and exp[2][0] == :lasgn and @collnames.size > 1 and exp[1] # join iter with lefts/rights
|
158
156
|
case exp[1][2]
|
159
157
|
when :lefts
|
160
|
-
@iterhash[exp[2][1]] = @collnames[0]
|
158
|
+
@iterhash[exp[2][1]] = @collnames[0]
|
161
159
|
when :rights
|
162
160
|
@iterhash[exp[2][1]] = @collnames[1]
|
163
161
|
else
|
@@ -189,10 +187,10 @@ class AttrNameRewriter < SexpProcessor # :nodoc: all
|
|
189
187
|
if recv and recv.class == Sexp and recv.first == :lvar and recv[1] and @iterhash[recv[1]]
|
190
188
|
if @bud_instance.respond_to?(@iterhash[recv[1]])
|
191
189
|
if @bud_instance.send(@iterhash[recv[1]]).class <= Bud::BudCollection
|
192
|
-
|
190
|
+
cols = @bud_instance.send(@iterhash[recv[1]]).cols
|
193
191
|
if op != :[] and @bud_instance.send(@iterhash[recv[1]]).respond_to?(op)
|
194
192
|
# if the op is an attribute name in the schema, col is its index
|
195
|
-
col =
|
193
|
+
col = cols.index(op) unless cols.nil?
|
196
194
|
unless col.nil?
|
197
195
|
op = :[]
|
198
196
|
args = s(:arglist, s(:lit, col))
|
@@ -348,7 +346,7 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
348
346
|
end
|
349
347
|
|
350
348
|
_, recv, meth, meth_args = n
|
351
|
-
if meth == @keyword and recv.nil?
|
349
|
+
if meth == @keyword and recv.nil?
|
352
350
|
block[i] = rewrite_me(n)
|
353
351
|
@did_work = true
|
354
352
|
end
|
@@ -366,9 +364,10 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
366
364
|
_, lhs, op, rhs = meth_args.sexp_body.first
|
367
365
|
|
368
366
|
old_rhs_body = rhs.sexp_body
|
369
|
-
|
370
|
-
|
371
|
-
|
367
|
+
new_rhs_body = [:iter]
|
368
|
+
new_rhs_body += old_rhs_body
|
369
|
+
new_rhs_body += iter_body[1..-1]
|
370
|
+
rhs[1] = Sexp.from_array(new_rhs_body)
|
372
371
|
return call_node
|
373
372
|
end
|
374
373
|
end
|
@@ -468,7 +467,7 @@ class WithExpander < TempExpander
|
|
468
467
|
meth_name = Module.make_state_meth_name(klass).to_s + "__" + @keyword.to_s
|
469
468
|
return s(:defn, meth_name.to_sym, s(:args), s(:scope, block))
|
470
469
|
end
|
471
|
-
|
470
|
+
|
472
471
|
private
|
473
472
|
def rewrite_me(exp)
|
474
473
|
_, recv, meth, args = exp
|
@@ -490,10 +489,10 @@ class WithExpander < TempExpander
|
|
490
489
|
@with_rules.push nest_block
|
491
490
|
new_recv = s(:call, nil, tmp_name, s(:arglist))
|
492
491
|
return s(:call, new_recv, nest_op, nest_args)
|
493
|
-
end
|
494
|
-
|
492
|
+
end
|
493
|
+
|
495
494
|
undef get_state_meth
|
496
|
-
|
495
|
+
|
497
496
|
public
|
498
497
|
def get_state_meth(klass)
|
499
498
|
return if @tmp_tables.empty?
|
@@ -558,24 +557,24 @@ module ModuleRewriter # :nodoc: all
|
|
558
557
|
# the import site. Note that additional rewrites are needed to ensure that
|
559
558
|
# code in the import site that accesses module contents does the right thing;
|
560
559
|
# see Bud#rewrite_local_methods.
|
561
|
-
|
560
|
+
|
562
561
|
@@with_id = 0 # upon initialize
|
563
562
|
def self.with_id
|
564
563
|
@@with_id
|
565
564
|
end
|
566
|
-
|
565
|
+
|
567
566
|
def self.incr_with_id
|
568
567
|
@@with_id += 1
|
569
568
|
end
|
570
|
-
|
569
|
+
|
571
570
|
def self.do_import(import_site, mod, local_name)
|
572
|
-
# ast_process_withs modifies its argument as a side-effect
|
571
|
+
# ast_process_withs modifies its argument as a side-effect
|
573
572
|
# and returns a matching ast.
|
574
573
|
# hence we run it before the other rewrites.
|
575
574
|
ast = ast_process_withs(mod)
|
576
575
|
ast = ast_flatten_nested_refs(ast, mod.bud_import_table)
|
577
576
|
ast = ast_process_temps(ast, mod)
|
578
|
-
|
577
|
+
|
579
578
|
ast, new_mod_name = ast_rename_module(ast, import_site, mod, local_name)
|
580
579
|
rename_tbl = {}
|
581
580
|
ast = ast_rename_methods(ast, local_name, rename_tbl)
|
@@ -584,14 +583,14 @@ module ModuleRewriter # :nodoc: all
|
|
584
583
|
|
585
584
|
str = Ruby2Ruby.new.process(ast)
|
586
585
|
rv = import_site.module_eval str
|
587
|
-
raise Bud::
|
586
|
+
raise Bud::CompileError unless rv.nil?
|
588
587
|
return new_mod_name
|
589
588
|
end
|
590
589
|
|
591
590
|
def self.get_module_ast(mod)
|
592
591
|
raw_ast = get_raw_parse_tree(mod)
|
593
592
|
unless raw_ast.first == :module
|
594
|
-
raise Bud::
|
593
|
+
raise Bud::CompileError, "import must be used with a Module"
|
595
594
|
end
|
596
595
|
|
597
596
|
return Unifier.new.process(raw_ast)
|
@@ -668,16 +667,16 @@ module ModuleRewriter # :nodoc: all
|
|
668
667
|
end
|
669
668
|
return ast
|
670
669
|
end
|
671
|
-
|
670
|
+
|
672
671
|
def self.ast_mangle_with(w,klass)
|
673
672
|
r2r = Ruby2Ruby.new
|
674
|
-
|
673
|
+
|
675
674
|
while st = w.get_state_meth(klass)
|
676
675
|
# generate the module
|
677
676
|
tmpmod = Module.new
|
678
677
|
|
679
678
|
# add a state block to define a temp for the collection name
|
680
|
-
state_src = r2r.process(st)
|
679
|
+
state_src = r2r.process(st)
|
681
680
|
tmpmod.module_eval(state_src)
|
682
681
|
|
683
682
|
# add a bloom block
|
@@ -697,13 +696,13 @@ module ModuleRewriter # :nodoc: all
|
|
697
696
|
|
698
697
|
# eval all that Ruby we generated and import new Module into our code
|
699
698
|
tmpmod.module_eval(bloom_src)
|
700
|
-
modname = "with__
|
699
|
+
modname = "with__#{ModuleRewriter.with_id.to_s}"
|
701
700
|
klass.import tmpmod => modname.to_sym
|
702
701
|
|
703
702
|
ModuleRewriter.incr_with_id
|
704
703
|
end
|
705
704
|
end
|
706
|
-
|
705
|
+
|
707
706
|
def self.ast_process_withs(mod)
|
708
707
|
# strategy to handle withs:
|
709
708
|
# 1) run WithExpander#process to delete the "with" blocks and extract their contents
|
@@ -716,9 +715,9 @@ module ModuleRewriter # :nodoc: all
|
|
716
715
|
ast = w.process(ast)
|
717
716
|
mod_s, name_s, blocks = ast[0], ast[1], ast[2..-1]
|
718
717
|
tag, name, args, scope = blocks[0]
|
719
|
-
|
720
|
-
self.ast_mangle_with(w,mod)
|
721
|
-
|
718
|
+
|
719
|
+
self.ast_mangle_with(w, mod)
|
720
|
+
|
722
721
|
retval = Unifier.new.process(self.get_raw_parse_tree(mod))
|
723
722
|
return retval
|
724
723
|
# return s(mod_s, name_s, *blocks)
|
@@ -730,7 +729,7 @@ module ModuleRewriter # :nodoc: all
|
|
730
729
|
# "bootstrap", and "bloom" methods).
|
731
730
|
def self.ast_rename_module(ast, importer, importee, local_name)
|
732
731
|
mod_name = ast.sexp_body.first
|
733
|
-
raise Bud::
|
732
|
+
raise Bud::CompileError if mod_name.to_s != importee.to_s
|
734
733
|
|
735
734
|
# If the importer or importee modules are nested inside an outer module,
|
736
735
|
# strip off the outer module name before using for name mangling purposes
|
@@ -752,7 +751,7 @@ module ModuleRewriter # :nodoc: all
|
|
752
751
|
# given module's AST. Returns a table mapping old => new names.
|
753
752
|
def self.ast_rename_state(ast, local_name, rename_tbl)
|
754
753
|
# Find all the state blocks in the AST
|
755
|
-
raise Bud::
|
754
|
+
raise Bud::CompileError unless ast.sexp_type == :module
|
756
755
|
|
757
756
|
ast.sexp_body.each do |b|
|
758
757
|
next unless b.class <= Sexp
|
@@ -761,17 +760,17 @@ module ModuleRewriter # :nodoc: all
|
|
761
760
|
def_name, args, scope = b.sexp_body
|
762
761
|
next unless /^__state\d+__/.match def_name.to_s
|
763
762
|
|
764
|
-
raise Bud::
|
763
|
+
raise Bud::CompileError unless scope.sexp_type == :scope
|
765
764
|
state_block = scope.sexp_body.first
|
766
|
-
raise Bud::
|
765
|
+
raise Bud::CompileError unless state_block.sexp_type == :block
|
767
766
|
next unless state_block.sexp_body
|
768
767
|
|
769
768
|
# Look for collection definition statements inside the block
|
770
769
|
state_block.sexp_body.each do |e|
|
771
|
-
raise Bud::
|
770
|
+
raise Bud::CompileError unless e.sexp_type == :call
|
772
771
|
|
773
772
|
recv, meth_name, args = e.sexp_body
|
774
|
-
raise Bud::
|
773
|
+
raise Bud::CompileError unless args.sexp_type == :arglist
|
775
774
|
|
776
775
|
if meth_name == :interface
|
777
776
|
tbl_name_node = args.sexp_body[1]
|
@@ -779,7 +778,9 @@ module ModuleRewriter # :nodoc: all
|
|
779
778
|
tbl_name_node = args.sexp_body[0]
|
780
779
|
end
|
781
780
|
|
782
|
-
|
781
|
+
if tbl_name_node.nil? or tbl_name_node.sexp_type != :lit
|
782
|
+
raise Bud::CompileError, "syntax error in state block"
|
783
|
+
end
|
783
784
|
tbl_name = tbl_name_node.sexp_body.first
|
784
785
|
|
785
786
|
new_tbl_name = "#{local_name}__#{tbl_name}".to_sym
|