bud 0.0.5 → 0.0.6

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.
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
- @internals = {'localtick' => 1, 'stdio' => 1}
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
- # hack attack
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.to_s)] or k.to_s =~ /_tbl/ or @internals[k.to_s] or (k.to_s =~ /^t_/ and @budtime != 0)
186
- addonce(k.to_s, false)
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.to_s, false, false, false)
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}_/tm_#{item}.svg"
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.schema & s.schema
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.schema}.flatten(1)
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
- self.map{|r1, r2| ["\[ #{r1.inspect} #{r2.inspect} \]"]}
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
- @schema = rels[0].schema
223
+ @cols = @rels[0].cols
222
224
  setup_preds(preds)
223
225
  setup_state if self.class <= Bud::BudJoin
224
- if @bud_instance.stratum_first_iter
225
- @matches = map { |r, s| (blk.nil?) ? r : blk.call(r,s) }.compact
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
- unless tabnames.include? p[0][0] and tabnames.include? p[1][0]
243
- raise Bud::CompileError, "illegal predicate: collection #{} is not being joined"
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]
@@ -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, "Bloom block names must be a symbol: #{block_name}"
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, "Duplicate named bloom block: '#{block_name}' in #{self}"
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]:\texecutes x (or 1) timesteps"],
26
+ "tick [x]\texecutes x (or 1) timesteps"],
27
27
 
28
28
  "run" => [lambda {|lib,_| lib.run},
29
- "run:\ttick until quiescence, a breakpoint, or #{@@escape_char}stop"],
29
+ "run\ttick until quiescence, a breakpoint, or #{@@escape_char}stop"],
30
30
 
31
31
  "stop" => [lambda {|lib,_| lib.stop},
32
- "stop:\tstop ticking"],
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:\tlist rules"],
35
+ "lsrules\tlist rules"],
36
36
 
37
37
  "rmrule" => [lambda {|lib,argv| lib.del_rule(Integer(argv[1]))},
38
- "rmrule x:\tremove rule number 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:\tlist collections"],
41
+ "lscollections\tlist collections"],
42
42
 
43
43
  "dump" => [lambda {|lib,argv| lib.dump(argv[1])},
44
- "dump c:\tdump contents of collection c"],
44
+ "dump c\tdump contents of collection c"],
45
45
 
46
- "exit" => [lambda {|_,_| do_exit}, "exit:\texit rebl"],
46
+ "exit" => [lambda {|_,_| do_exit}, "exit\texit rebl"],
47
47
 
48
- "quit" => [lambda {|_,_| do_exit}, "quit:\texit rebl"],
48
+ "quit" => [lambda {|_,_| do_exit}, "quit\texit rebl"],
49
49
 
50
50
  "help" => [lambda {|_,_| pretty_help},
51
- "help:\tprint this help message"]}
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 + 3 - v[1].split(':')[0].size))
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
- tups = @rebl_class_inst.instance_eval("#{c}.inspected")
232
- puts(tups.empty? ? "(empty)" : tups.sort.join("\n"))
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, :payloads => 1, :~ => 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
- schema = @bud_instance.send(recv[2]).schema
29
- if schema and schema.include? op
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
- schema = @bud_instance.send(@iterhash[recv[1]]).schema
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 = schema.index(op) unless schema.nil?
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
- rhs[1] = s(:iter)
370
- rhs[1] += old_rhs_body
371
- rhs[1] += iter_body[1..-1]
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::BudError unless rv.nil?
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::BudError, "import must be used with a Module"
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__"+ModuleRewriter.with_id.to_s
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::BudError if mod_name.to_s != importee.to_s
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::BudError unless ast.sexp_type == :module
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::BudError unless scope.sexp_type == :scope
763
+ raise Bud::CompileError unless scope.sexp_type == :scope
765
764
  state_block = scope.sexp_body.first
766
- raise Bud::BudError unless state_block.sexp_type == :block
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::BudError unless e.sexp_type == :call
770
+ raise Bud::CompileError unless e.sexp_type == :call
772
771
 
773
772
  recv, meth_name, args = e.sexp_body
774
- raise Bud::BudError unless args.sexp_type == :arglist
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
- raise Bud::BudError unless tbl_name_node.sexp_type == :lit
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