bud 0.0.8 → 0.1.0.pre1

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/joins.rb CHANGED
@@ -1,3 +1,4 @@
1
+ $EMPTY = []
1
2
  module Bud
2
3
  class BudJoin < BudCollection
3
4
  attr_accessor :rels, :origrels, :origpreds # :nodoc: all
@@ -106,7 +107,7 @@ module Bud
106
107
  flat_schema = @rels.map{|r| r.cols}.flatten(1)
107
108
  dupfree_schema = []
108
109
  # while loop here (inefficiently) ensures no collisions
109
- while dupfree_schema == [] or dupfree_schema.uniq.length < dupfree_schema.length
110
+ while dupfree_schema == $EMPTY or dupfree_schema.uniq.length < dupfree_schema.length
110
111
  dupfree_schema = []
111
112
  flat_schema.reduce({}) do |memo, r|
112
113
  if r.to_s.include?("_") and ((r.to_s.rpartition("_")[2] =~ /^\d+$/) == 0)
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'bud'
3
- require 'bud/depanalysis'
4
3
 
5
4
  module MetaAlgebra
6
5
  state do
@@ -48,6 +47,7 @@ module MetaAlgebra
48
47
  #stdio <~ seq_lattice_closure{|c| ["SLC: #{c.inspect}"]}
49
48
  #stdio <~ jlr {|j| ["JLR: #{j.inspect}"]}
50
49
  #stdio <~ lub {|l| ["LUB #{l.inspect}, left class #{l.left.class}"]}
50
+ #stdio <~ clean_dep.inspected
51
51
  end
52
52
 
53
53
  bloom :lattice_rules do
@@ -92,10 +92,11 @@ module MetaAlgebra
92
92
  end
93
93
 
94
94
  bloom :make_paths do
95
- rule_nm <= t_depends.reduce({}) do |memo, i|
95
+ rule_nm <= t_depends.reduce(Hash.new) do |memo, i|
96
96
  tag = get_tag(i.nm, i.op)
97
- memo[i.rule_id] = tag if memo[i.rule_id].nil?
98
- memo[i.rule_id] = tag if tag == :N or tag == :A
97
+ if memo[i.rule_id].nil? or memo[i.rule_id] == :M
98
+ memo[i.rule_id] = tag
99
+ end
99
100
  memo
100
101
  end
101
102
 
data/lib/bud/metrics.rb CHANGED
@@ -1,5 +1,11 @@
1
- require 'bud/errors'
2
- require 'faster_csv'
1
+ require "bud/errors"
2
+ if RUBY_VERSION <= "1.9"
3
+ require 'faster_csv'
4
+ $mod = FasterCSV
5
+ else
6
+ require 'csv'
7
+ $mod = CSV
8
+ end
3
9
 
4
10
  # metrics are reported in a nested hash representing a collection of relational tables.
5
11
  # The metrics hash has the following form:
@@ -14,7 +20,7 @@ require 'faster_csv'
14
20
  def report_metrics
15
21
  metrics.each do |k,v|
16
22
  if v.first
17
- csvstr = FasterCSV.generate(:force_quotes=>true) do |csv|
23
+ csvstr = $mod.generate(:force_quotes=>true) do |csv|
18
24
  csv << [k.to_s] + v.first[0].keys + [:val]
19
25
  v.each do |row|
20
26
  csv << [nil] + row[0].values + [row[1]]
@@ -1,33 +1,129 @@
1
1
  # We monkeypatch Module to add support for Bloom's syntax additions: "state",
2
2
  # "bloom", and "bootstrap" blocks, plus the "import" statement.
3
+
4
+ require 'bud/source'
5
+
6
+ class Class
7
+ def modules
8
+ a = self.ancestors
9
+ a[1..a.index(superclass)-1]
10
+ end
11
+ end
12
+
13
+ # FIXME: Use a subclass of Struct.
14
+ class Struct
15
+ def <=>(o)
16
+ if o.class == self.class
17
+ self.each_with_index do |e, i|
18
+ cmp = e <=> o[i]
19
+ return cmp if cmp != 0
20
+ end
21
+ return 0
22
+ elsif o.nil?
23
+ return -1
24
+ else
25
+ raise "Comparison (<=>) between #{o.class} and #{self.class} not implemented"
26
+ end
27
+ end
28
+
29
+ alias oldeq :==
30
+ def ==(o)
31
+ if o.class == self.class
32
+ return oldeq(o)
33
+ elsif o.class == Array
34
+ begin
35
+ self.each_with_index do |el, i|
36
+ if el != o[i]
37
+ return false
38
+ end
39
+ end
40
+ return true
41
+ rescue StandardError
42
+ return false
43
+ end
44
+ end
45
+ false
46
+ end
47
+
48
+ def to_msgpack(out='')
49
+ self.to_a.to_msgpack(out)
50
+ end
51
+
52
+ def inspect
53
+ self.to_a.inspect
54
+ end
55
+
56
+ alias :to_s :inspect
57
+ end
58
+
59
+ # XXX: TEMPORARY/UGLY hack to ensure that arrays and structs compare. This can be
60
+ # removed once tests are rewritten.
61
+ class Array
62
+ alias :oldeq :==
63
+ def ==(o)
64
+ if o.kind_of? Struct
65
+ o = (o.to_a)
66
+ end
67
+ self.oldeq(o)
68
+ end
69
+ end
70
+
71
+
72
+ $moduleWrapper = {} # module => wrapper class. See import below.
3
73
  class Module
74
+ def modules
75
+ ancestors[1..-1]
76
+ end
77
+
4
78
  # import another module and assign to a qualifier symbol: <tt>import MyModule => :m</tt>
5
79
  def import(spec)
6
80
  raise Bud::CompileError unless (spec.class <= Hash and spec.length == 1)
7
81
  mod, local_name = spec.first
8
82
  raise Bud::CompileError unless (mod.class <= Module and local_name.class <= Symbol)
9
83
 
10
- # Attempting to import a module that has already included the Bud module
11
- # results in problems (and is a bad idea anyway), so disallow it.
12
- if mod.included_modules.include? Bud
13
- raise Bud::CompileError, "cannot import #{mod} because it has already included Bud"
84
+ # A statement like this:
85
+ # import MyModule => :m
86
+ # is translated as follows. First, module MyModule is made instantiable by wrapping it in a class
87
+ # class MyModule__wrap__
88
+ # include Bud
89
+ # include MyModule
90
+ # end
91
+ #
92
+ # Then introduce a method "m", the import binding name, in the calling module/class
93
+ # (the one with the import statement). This returns an instance of the wrapped class.
94
+ # inst = MyModule__wrap__.new
95
+ # def m
96
+ # inst
97
+ # end
98
+
99
+ mod, local_name = spec.first
100
+
101
+ if self.instance_methods.include? local_name.to_s or self.instance_methods.include? local_name
102
+ raise Bud::CompileError, "#{local_name} is already taken."
103
+ else
104
+ src = %Q{
105
+ def #{local_name}
106
+ @#{local_name}
107
+ end
108
+ def #{local_name}=(val)
109
+ raise "Type Error: expecting an instance of #{mod}" unless val.kind_of? #{mod}
110
+ @#{local_name} = val
111
+ end
112
+ }
113
+ #puts src
114
+ self.class_eval src
14
115
  end
15
116
 
16
- # To correctly expand qualified references to an imported module, we keep a
17
- # table with the local bind names of all the modules imported by this
18
- # module. To handle nested references (a.b.c.d etc.), the import table for
19
- # module X points to X's own nested import table. If a single module
20
- # attempts to import multiple sub-modules with the same local name, we merge
21
- # the import tables of all the modules.
22
- @bud_import_tbl ||= {}
23
- prev_tbl = @bud_import_tbl[local_name]
24
- child_tbl = NestedRefRewriter.build_import_table(mod)
25
- @bud_import_tbl[local_name] = NestedRefRewriter.merge_import_table(prev_tbl, child_tbl)
117
+ import_tbl = self.bud_import_table
118
+ import_tbl[local_name] = mod
119
+ end
26
120
 
27
- rewritten_mod_name = ModuleRewriter.do_import(self, mod, local_name)
28
- self.module_eval "include #{rewritten_mod_name}"
121
+ def bud_import_table() #:nodoc: all
122
+ @bud_import_tbl ||= {}
123
+ @bud_import_tbl
29
124
  end
30
125
 
126
+
31
127
  # the block of Bloom collection declarations. one per module.
32
128
  def state(&block)
33
129
  meth_name = Module.make_state_meth_name(self)
@@ -64,12 +160,22 @@ class Module
64
160
  if instance_methods(false).include? meth_name
65
161
  raise Bud::CompileError, "duplicate named bloom block: '#{block_name}' in #{self}"
66
162
  end
67
- define_method(meth_name.to_sym, &block)
68
- end
69
-
70
- def bud_import_table() #:nodoc: all
71
- @bud_import_tbl ||= {}
72
- @bud_import_tbl
163
+ ast = Source.read_block(caller[0]) # pass in caller's location via backtrace
164
+ # ast corresponds only to the statements of the block. Wrap it in a method
165
+ # definition for backward compatibility for now.
166
+ # First wrap ast in a block if it is only a single statement
167
+ unless ast.nil?
168
+ ast = s(:block, ast) unless ast.sexp_type == :block
169
+ ast = s(:defn, meth_name.to_sym, s(:args), s(:scope, ast))
170
+ unless self.respond_to? :__bloom_asts__
171
+ def self.__bloom_asts__;
172
+ @__bloom_asts__ ||= {}
173
+ @__bloom_asts__
174
+ end
175
+ end
176
+ __bloom_asts__[meth_name] = ast
177
+ define_method(meth_name.to_sym, &block)
178
+ end
73
179
  end
74
180
 
75
181
  private
@@ -78,7 +184,9 @@ class Module
78
184
  # class/module Y, X's class name is the string "Y::X". We don't want to define
79
185
  # method names with semicolons in them, so just return "X" instead.
80
186
  def self.get_class_name(klass)
81
- klass.name.split("::").last
187
+ (klass.name.nil? or klass.name == "") \
188
+ ? "Anon#{klass.object_id}" \
189
+ : klass.name.split("::").last
82
190
  end
83
191
 
84
192
  # State method blocks are named using an auto-incrementing counter. This is to
data/lib/bud/rebl.rb CHANGED
@@ -3,11 +3,11 @@ require 'readline'
3
3
  require 'rubygems'
4
4
  require 'bud'
5
5
  require 'abbrev'
6
-
6
+ require 'tempfile'
7
7
  TABLE_TYPES = ["table", "scratch", "channel", "loopback", "periodic", "sync", "store"]
8
8
 
9
9
  # The class to which rebl adds user-specified rules and declarations.
10
- class ReblClass
10
+ class ReblBase
11
11
  include Bud
12
12
  attr_accessor:port, :ip
13
13
 
@@ -22,8 +22,8 @@ class ReblShell
22
22
  @@maxhistsize = 100
23
23
  @@escape_char = '/'
24
24
  @@commands =
25
- {"tick" => [lambda {|lib,argv| lib.tick([Integer(argv[1]), 1].max)},
26
- "tick [x]\texecutes x (or 1) timesteps"],
25
+ {"tick" => [lambda {|lib,argv| lib.tick(argv[1].nil? ? 1 : Integer(argv[1]))},
26
+ "tick [x]:\texecutes x (or 1) timesteps"],
27
27
 
28
28
  "run" => [lambda {|lib,_| lib.run},
29
29
  "run\ttick until quiescence, a breakpoint, or #{@@escape_char}stop"],
@@ -62,8 +62,9 @@ class ReblShell
62
62
  loop do
63
63
  begin
64
64
  rebl_loop(lib)
65
- rescue Exception
66
- puts "exception: #{$!}"
65
+ rescue Exception => e
66
+ puts "exception: #{e}"
67
+ #puts e.backtrace
67
68
  end
68
69
  end
69
70
  end
@@ -197,6 +198,7 @@ class LibRebl
197
198
  @@builtin_tables = [:stdio, :t_depends, :periodics_tbl, :t_cycle, :localtick,
198
199
  :t_provides, :t_rules, :t_depends_tc, :t_stratum,
199
200
  :rebl_breakpoint]
201
+ @@classid = 0
200
202
 
201
203
  def initialize(ip, port)
202
204
  @ip = ip
@@ -222,7 +224,7 @@ class LibRebl
222
224
  end
223
225
 
224
226
  # Ticks the bud instance a specified integer number of times.
225
- def tick(x)
227
+ def tick(x=1)
226
228
  x.times {@rebl_class_inst.sync_do}
227
229
  end
228
230
 
@@ -234,13 +236,7 @@ class LibRebl
234
236
  puts "Error: non-existent collection \"#{c}\""
235
237
  else
236
238
  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
239
+ puts(tups.empty? ? "(empty)" : tups.sort.map{|t| "#{t}"}.join("\n"))
244
240
  end
245
241
  end
246
242
 
@@ -278,22 +274,40 @@ class LibRebl
278
274
  end
279
275
  end
280
276
 
281
- private
282
- def reinstantiate
283
- # New anonymous subclass.
284
- @rebl_class = Class.new(ReblClass)
285
-
277
+ def mk_rebl_class
278
+ @@classid += 1
279
+ cls_name = "ReblClass#{@@classid}"
280
+
281
+ str = ""
282
+ str =<<-EOS
283
+ $BUD_SAFE=1
284
+ class #{cls_name} < ReblBase
285
+ include Bud
286
+ EOS
287
+ unless @state.empty?
288
+ str += "state do\n" + @state.values.join("\n") + "\nend\n"
289
+ end
290
+ unless @rules.empty?
291
+ str += "bloom :rebl_rules do\n" + @rules.sort.map {|_,r| r}.join("\n") + "\nend\n"
292
+ end
293
+ str += "\nend\n"
294
+ f = Tempfile.new("rebl")
295
+ f.write(str)
296
+ f.close
286
297
  begin
287
- if not @rules.empty?
288
- @rebl_class.class_eval("bloom :rebl_rules do\n" +
289
- @rules.sort.map {|_,r| r}.join("\n") + "\nend")
290
- end
291
- if not @state.empty?
292
- @rebl_class.class_eval("state do\n" + @state.values.join("\n") + "\nend")
293
- end
294
- rescue Exception
298
+ load f.path
299
+ return eval cls_name # return the class object
300
+ rescue
301
+ $stderr.puts "Unable to eval the following code:\n" + str
295
302
  raise
303
+ ensure
304
+ f.unlink
296
305
  end
306
+ end
307
+
308
+ private
309
+ def reinstantiate
310
+ @rebl_class = mk_rebl_class
297
311
 
298
312
  @old_inst = @rebl_class_inst
299
313
  @rebl_class_inst = @rebl_class.new(:signal_handling => :none, :ip => @ip,
@@ -314,7 +328,6 @@ class LibRebl
314
328
  @rebl_class_inst.channels.merge!(@old_inst.channels.reject do |k,v|
315
329
  @@builtin_tables.include? k
316
330
  end)
317
- @rebl_class_inst.tc_tables.merge! @old_inst.tc_tables
318
331
  @rebl_class_inst.dbm_tables.merge! @old_inst.dbm_tables
319
332
  @rebl_class_inst.zk_tables.merge! @old_inst.zk_tables
320
333