bud 0.0.8 → 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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