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/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