bud 0.9.5 → 0.9.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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MTY4MjlkMTY1NjZlYTZiOTVjNmYyMmIzYTliNDVlZDIwZjA0YjY4Yw==
5
+ data.tar.gz: !binary |-
6
+ MTE0ZGY3MDg5NzBmMTJkYTExNDNjYTcyNTFhOThmMzk0ZTM4YzgxOA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ OGJmYmMwZjU4Y2RlZWUyNDVkMGFkYTczZDhlNjk5MGQ5NmVlZDIyYzQyMjAz
10
+ NzEyZWI0YTI1MjVjM2VhZGRjMWE4ZDM4MGVlYzA4YzliYmJjNGUwZjEyY2I2
11
+ YjZhOTVjNzk5MGVjNWJkMTA0YWRmODk3MDAyYmVlOTM4MmVmYzA=
12
+ data.tar.gz: !binary |-
13
+ YjZkOTlkYzQwODJkZTI4YjU0YmFhMmY4MDY5Mjg3Y2ZjMzUyN2ZmZTAyOGI5
14
+ M2M3NWQ5OTgyM2U2ZjA3NGIzMjkwZjhjMTBhNWFmYzc3OTNiYmZjOWMzNmU3
15
+ MTkzZmI1MzJlODNkMmE2Y2E1NzU5ODYzNDlhM2Q3N2Q3MDk2Yzg=
data/History.txt CHANGED
@@ -1,8 +1,32 @@
1
+ == 0.9.6 / 2013-02-25
2
+
3
+ * Support syntax sugar for initializing lattices (#294). For example, rather
4
+ than writing "foo <= Bud::MaxLattice.new(2)", you can now just write "foo <=
5
+ 2". Note that, due to a bug in the superator gem, you cannot use this syntax
6
+ with the <+ operator.
7
+ * Allow nested lattice values to be sent over channels (#295, patch from Josh
8
+ Rosen). Lattice values could previously be sent as a field value in a tuple
9
+ delivered over a channel, but they could not be embedded arbitrarily deeply
10
+ within tuples (e.g., lattices nested within an array could not previously be
11
+ sent as a field value).
12
+ * Support "Comparable" for Bud::Lattice values
13
+ * Add support for lattices to rebl
14
+ * Reject attempts to insert into stdio via <+ (#288)
15
+ * Restore functionality of reading from stdio (i.e., stdin) with MRI 1.9
16
+ * Improve MRI 1.8 compatibility
17
+ * Require ruby_parser >= 3.1.0
18
+ * Fix bug in bootstrap blocks for lattice values
19
+ * Fix bug in rescan/invalidation for rules that reference lattice values and use
20
+ the <+ or <~ operators (#290)
21
+ * Fix bug in rescan logic for notin operator (#291)
22
+ * Fix bug in notin operators involving self joins (#298)
23
+ * Fix error when output from a notin operator was fed into a lattice
24
+
1
25
  == 0.9.5 / 2012-11-24
2
26
 
3
27
  * Lattice branch (Bloom^L) merged
4
28
  * Compatibility with recent versions of ruby_parser (3.0.2+) and ruby2ruby
5
- (2.0.1+) -- #. Older versions of these two gems are no longer supported
29
+ (2.0.1+). Older versions of these two gems are no longer supported
6
30
  * Add support for aggregate functions that take multiple input columns
7
31
  * Add built-in aggregate function accum_pair(x, y), which produces a Set of
8
32
  pairs (two-element arrays [x,y])
data/bin/budlabel CHANGED
File without changes
data/bin/budplot CHANGED
@@ -77,8 +77,8 @@ def process(mods)
77
77
  d = make_instance(mods)
78
78
 
79
79
  interfaces = {}
80
- d.t_provides.each do |name, is_input|
81
- interfaces[name] = is_input
80
+ d.t_provides.to_a.each do |prov|
81
+ interfaces[prov.interface] = prov.input
82
82
  end
83
83
 
84
84
  tabinf = {}
@@ -201,13 +201,18 @@ def get_trace_data
201
201
  end
202
202
 
203
203
  if ARGV.length < 2
204
- puts "Usage: budplot LIST_OF_FILES LIST_OF_MODULES_OR_CLASSES"
204
+ puts "Usage: budplot [-I PATH_TO_RUBY_INCLUDES] LIST_OF_FILES LIST_OF_MODULES_OR_CLASSES"
205
205
  exit
206
206
  end
207
207
 
208
- @opts = Getopt::Std.getopts("t:")
209
-
210
-
208
+ @opts = Getopt::Std.getopts("I:t:")
209
+ unless @opts["I"].nil?
210
+ if @opts["I"].class == Array
211
+ @opts["I"].each{|i| $:.unshift i}
212
+ else
213
+ $:.unshift @opts["I"]
214
+ end
215
+ end
211
216
 
212
217
  @data = get_trace_data
213
218
  `mkdir bud_doc`
data/bin/budtimelines CHANGED
@@ -10,7 +10,7 @@ include VizUtil
10
10
 
11
11
  module Depends
12
12
  state do
13
- table :depends, [:rid, :lhs, :op, :rhs, :nm, :in_body]
13
+ table :depends, [:bud_obj, :rid, :lhs, :op, :rhs, :nm, :in_body]
14
14
  end
15
15
  end
16
16
 
@@ -49,7 +49,7 @@ end
49
49
  module DeltaLogic
50
50
  include TPSchema
51
51
  bloom do
52
- zerod_cards <= cardinalities{|c| c + [c.bud_time-1]}
52
+ zerod_cards <= cardinalities{|c| c.to_a + [c.bud_time-1]}
53
53
  zerod_cards <= (times * depends).pairs do |t, d|
54
54
  unless cardinalities{|c| c[1] if c[0] == t.bud_time}.include? d[1]
55
55
  [t.bud_time, d[1], 0, t.bud_time - 1]
data/bin/budvis CHANGED
@@ -28,7 +28,13 @@ usage unless ARGV[0]
28
28
  usage if ARGV[0] == '--help'
29
29
 
30
30
  meta, data = get_meta2(BUD_DBM_DIR)
31
- vh = VizHelper.new(meta[:tabinf], meta[:cycle], meta[:depends], meta[:rules], ARGV[0], meta[:provides])
31
+
32
+ # prune outbufs from tabinf
33
+ tabinf = meta[:tabinf].find_all do |k|
34
+ !(k[1] == "Bud::BudChannel" and k[0] =~ /_snd\z/)
35
+ end
36
+
37
+ vh = VizHelper.new(tabinf, meta[:cycle], meta[:depends], meta[:rules], ARGV[0], meta[:provides])
32
38
  data.each do |d|
33
39
  vh.full_info << d
34
40
  end
data/docs/README.md CHANGED
@@ -20,14 +20,14 @@ try the following:
20
20
  `budplot` tools for visualizing Bloom program analyses.
21
21
  * [bfs.md][bfs]: A walkthrough of the Bloom distributed filesystem.
22
22
 
23
- [intro]: /bloom-lang/bud/blob/master/docs/intro.md
24
- [getstarted]: /bloom-lang/bud/blob/master/docs/getstarted.md
25
- [operational]: /bloom-lang/bud/blob/master/docs/operational.md
26
- [cheat]: /bloom-lang/bud/blob/master/docs/cheat.md
27
- [modules]: /bloom-lang/bud/blob/master/docs/modules.md
28
- [ruby_hooks]: /bloom-lang/bud/blob/master/docs/ruby_hooks.md
29
- [visualizations]: /bloom-lang/bud/blob/master/docs/visualizations.md
30
- [bfs]: /bloom-lang/bud/blob/master/docs/bfs.md
23
+ [intro]: /docs/intro.md
24
+ [getstarted]: /docs/getstarted.md
25
+ [operational]: /docs/operational.md
26
+ [cheat]: /docs/cheat.md
27
+ [modules]: /docs/modules.md
28
+ [ruby_hooks]: /docs/ruby_hooks.md
29
+ [visualizations]: /docs/visualizations.md
30
+ [bfs]: /docs/bfs.md
31
31
 
32
32
  In addition, the [bud-sandbox](http://github.com/bloom-lang/bud-sandbox) GitHub
33
33
  repository contains lots of useful libraries and example programs built using
data/docs/cheat.md CHANGED
@@ -224,14 +224,14 @@ Output the facts in `bc` that do not appear in `bc2`, as follows. First, we form
224
224
  :attr2`).
225
225
 
226
226
  2. If a code block is specified, invoke the block on every pair of matching
227
- tuples in the join result. Any matches for which the block returns `nil`
227
+ tuples in the join result. Any matches for which the block returns `false`
228
228
  are removed from `t`.
229
229
 
230
230
  Finally, we output every tuple of `bc` that does *not* appear in `t`.
231
231
 
232
232
  # output items from foo if (a) there is no matching key in bar, or
233
233
  # (b) all matching keys in bar have a smaller value
234
- stdio <~ foo.notin(bar, :key=>:key) {|f, b| true if f.val <= b.val}
234
+ stdio <~ foo.notin(bar, :key=>:key) {|f, b| f.val <= b.val}
235
235
 
236
236
 
237
237
  ## SQL-style grouping/aggregation (and then some) ##
data/lib/bud.rb CHANGED
@@ -265,7 +265,7 @@ module Bud
265
265
  mod_inst.t_rules.each do |imp_rule|
266
266
  qname = "#{local_name}.#{imp_rule.lhs}"
267
267
  self.t_rules << [imp_rule.bud_obj, imp_rule.rule_id, qname, imp_rule.op,
268
- imp_rule.src, imp_rule.orig_src, imp_rule.nm_funcs_called]
268
+ imp_rule.src, imp_rule.orig_src, imp_rule.unsafe_funcs_called]
269
269
  end
270
270
  mod_inst.t_depends.each do |imp_dep|
271
271
  qlname = "#{local_name}.#{imp_dep.lhs}"
@@ -326,7 +326,7 @@ module Bud
326
326
  # the user-defined tables and lattices. We start @app_tables off as a set,
327
327
  # then convert to an array later.
328
328
  @app_tables = (@tables.keys - @builtin_tables.keys).map {|t| @tables[t]}.to_set
329
- @app_tables += @lattices.values
329
+ @app_tables.merge(@lattices.values)
330
330
 
331
331
  # Check scan and merge_targets to see if any builtin_tables need to be added as well.
332
332
  @scanners.each do |scs|
@@ -346,7 +346,7 @@ module Bud
346
346
  seen = Set.new(working)
347
347
  sorted_elems = [] # sorted elements in this stratum
348
348
  while not working.empty?
349
- sorted_elems += working
349
+ sorted_elems.concat(working)
350
350
  wired_to = []
351
351
  working.each do |e|
352
352
  e.wirings.each do |out|
@@ -453,18 +453,19 @@ module Bud
453
453
 
454
454
  # By default, all tables are considered sources unless they appear on the
455
455
  # lhs. We only consider non-temporal rules because invalidation is only
456
- # about this tick. Also, we track (in nm_targets) those tables that are the
457
- # targets of user-defined code blocks that call non-monotonic functions
458
- # (such as budtime). Elements that feed these tables are forced to rescan
459
- # their contents, and thus forced to re-execute these code blocks.
460
- nm_targets = Set.new
456
+ # about this tick. Also, we track (in unsafe_targets) those tables that are
457
+ # the targets of user-defined code blocks that call "unsafe" functions that
458
+ # produce a different value in every tick (e.g., budtime). Elements that
459
+ # feed these tables are forced to rescan their contents, and thus forced to
460
+ # re-execute these code blocks.
461
+ unsafe_targets = Set.new
461
462
  t_rules.each do |rule|
462
463
  lhs = rule.lhs.to_sym
463
464
  if rule.op == "<="
464
465
  # Note that lattices cannot be sources
465
466
  @tables[lhs].is_source = false if @tables.has_key? lhs
466
467
  end
467
- nm_targets << lhs if rule.nm_funcs_called
468
+ unsafe_targets << lhs if rule.unsafe_funcs_called
468
469
  end
469
470
 
470
471
  # Compute a set of tables and elements that should be explicitly told to
@@ -477,7 +478,7 @@ module Bud
477
478
  @push_sorted_elems[stratum].each do |elem|
478
479
  rescan << elem if elem.rescan_at_tick
479
480
 
480
- if elem.outputs.any?{|tab| not(tab.class <= PushElement) and not(tab.class <= LatticePushElement) and nm_targets.member? tab.qualified_tabname.to_sym }
481
+ if elem.outputs.any?{|tab| not(tab.class <= PushElement) and not(tab.class <= LatticePushElement) and unsafe_targets.member? tab.qualified_tabname.to_sym }
481
482
  rescan.merge(elem.wired_by)
482
483
  end
483
484
  end
@@ -489,8 +490,11 @@ module Bud
489
490
  @default_rescan = rescan.to_a
490
491
  @default_invalidate = invalidate.to_a
491
492
 
492
- puts "Default rescan: #{rescan.inspect}" if $BUD_DEBUG
493
- puts "Default inval: #{invalidate.inspect}" if $BUD_DEBUG
493
+ if $BUD_DEBUG
494
+ puts "Default rescan: #{rescan.inspect}"
495
+ puts "Default inval: #{invalidate.inspect}"
496
+ puts "Unsafe targets: #{unsafe_targets.inspect}"
497
+ end
494
498
 
495
499
  # Now compute for each table that is to be scanned, the set of dependent
496
500
  # tables and elements that will be invalidated if that table were to be
@@ -518,27 +522,43 @@ module Bud
518
522
  end
519
523
  @reset_list = to_reset.to_a
520
524
 
521
- # For each lattice, find the set of tables that should be rescanned when
522
- # there is a new delta for the lattice. That is, if we have a rule like:
525
+ # For each lattice, find the collections that should be rescanned when there
526
+ # is a new delta for the lattice. That is, if we have a rule like:
523
527
  # "t2 <= t1 {|t| [t.key, lat_foo]}", whenever there is a delta on lat_foo we
524
528
  # should rescan t1 (to produce tuples with the updated lat_foo value).
529
+ #
525
530
  # TODO:
526
- # (1) support non-join ops to be rescanned (+ tests) + lambdas
527
- # (2) if t1 is fed by rules r1 and r2 but only r1 references lattice x,
531
+ # (1) if t1 is fed by rules r1 and r2 but only r1 references lattice x,
528
532
  # don't trigger rescan of r2 on deltas for x (hard)
529
533
  t_depends.each do |dep|
530
- src, dst = dep.body.to_sym, dep.lhs.to_sym
531
- if @lattices.has_key? src and @tables.has_key? dst and dep.in_body
534
+ src, target_name = dep.body.to_sym, dep.lhs.to_sym
535
+ if @lattices.has_key? src and dep.in_body
532
536
  src_lat = @lattices[src]
533
- dst_tbl = @tables[dst]
534
- dst_tbl.non_temporal_predecessors.each do |e|
535
- src_lat.rescan_on_merge << e
537
+ if @tables.has_key? target_name
538
+ target = @tables[target_name]
539
+ else
540
+ target = @lattices[target_name]
541
+ end
542
+
543
+ # Conservatively, we rescan all the elements that feed the lhs (target)
544
+ # collection via positive (non-deletion) rules; we then also need to
545
+ # potentially rescan ancestors of those elements as well (e.g., setting
546
+ # a stateless PushElement to rescan does nothing; we want to tell its
547
+ # ancestor ScannerElement to rescan).
548
+ #
549
+ # XXX: do we need to consider all transitively reachable nodes for
550
+ # rescan?
551
+ lat_rescan = target.positive_predecessors.to_set
552
+ lat_inval = Set.new
553
+ target.positive_predecessors.each do |e|
554
+ e.add_rescan_invalidate(lat_rescan, lat_inval)
536
555
  end
556
+ src_lat.rescan_on_delta.merge(lat_rescan)
537
557
  end
538
558
  end
539
559
  end
540
560
 
541
- # given rescan, invalidate sets, compute transitive closure
561
+ # Given rescan, invalidate sets, compute transitive closure
542
562
  def rescan_invalidate_tc(stratum, rescan, invalidate)
543
563
  rescan_len = rescan.size
544
564
  invalidate_len = invalidate.size
@@ -1139,14 +1159,14 @@ module Bud
1139
1159
  @periodics = table :periodics_tbl, [:pername] => [:period]
1140
1160
 
1141
1161
  # for BUD reflection
1142
- table :t_rules, [:bud_obj, :rule_id] => [:lhs, :op, :src, :orig_src, :nm_funcs_called]
1162
+ table :t_cycle, [:predicate, :via, :neg, :temporal]
1143
1163
  table :t_depends, [:bud_obj, :rule_id, :lhs, :op, :body] => [:nm, :in_body]
1144
1164
  table :t_provides, [:interface] => [:input]
1145
- table :t_underspecified, t_provides.schema
1165
+ table :t_rules, [:bud_obj, :rule_id] => [:lhs, :op, :src, :orig_src, :unsafe_funcs_called]
1146
1166
  table :t_stratum, [:predicate] => [:stratum]
1147
- table :t_cycle, [:predicate, :via, :neg, :temporal]
1148
1167
  table :t_table_info, [:tab_name, :tab_type]
1149
1168
  table :t_table_schema, [:tab_name, :col_name, :ord, :loc]
1169
+ table :t_underspecified, t_provides.schema
1150
1170
 
1151
1171
  # Identify builtin tables as such
1152
1172
  @builtin_tables = @tables.clone if toplevel
@@ -1186,7 +1206,7 @@ module Bud
1186
1206
  begin
1187
1207
  eval_rule(rule.bud_obj, rule.src)
1188
1208
  rescue Exception => e
1189
- err_msg = "** Exception while wiring rule: #{rule.src}\n ****** #{e}"
1209
+ err_msg = "** Exception while wiring rule: #{rule.orig_src}\n ****** #{e}"
1190
1210
  # Create a new exception for accomodating err_msg, but reuse original backtrace
1191
1211
  new_e = (e.class <= Bud::Error) ? e.class.new(err_msg) : Bud::Error.new(err_msg)
1192
1212
  new_e.set_backtrace(e.backtrace)
@@ -52,7 +52,7 @@ module Bud
52
52
  # user-specified schema.
53
53
  @cols.each do |s|
54
54
  if s.to_s.start_with? "@"
55
- raise Bud::Error, "illegal use of location specifier (@) in column #{s} of non-channel collection #{tabname}"
55
+ raise Bud::CompileError, "illegal use of location specifier (@) in column #{s} of non-channel collection #{tabname}"
56
56
  end
57
57
  end
58
58
 
@@ -284,7 +284,12 @@ module Bud
284
284
 
285
285
  public
286
286
  def non_temporal_predecessors
287
- @wired_by.select {|elem| elem.outputs.include? self}
287
+ @wired_by.select {|e| e.outputs.include? self}
288
+ end
289
+
290
+ public
291
+ def positive_predecessors
292
+ @wired_by.select {|e| e.outputs.include?(self) || e.pendings.include?(self)}
288
293
  end
289
294
 
290
295
  public
@@ -869,6 +874,8 @@ module Bud
869
874
  given_schema ||= [:@address, :val]
870
875
  @is_loopback = loopback
871
876
  @locspec_idx = nil
877
+ @wire_buf = StringIO.new
878
+ @packer = MessagePack::Packer.new(@wire_buf)
872
879
 
873
880
  # We're going to mutate the caller's given_schema (to remove the location
874
881
  # specifier), so make a deep copy first. We also save a ref to the
@@ -959,19 +966,40 @@ module Bud
959
966
  # particular, lattice values and Class instances), we first encode such
960
967
  # values using Marshal, and then encode the entire tuple with
961
968
  # MsgPack. Obviously, this is gross. The wire format also includes an
962
- # array of indices, indicating which fields hold Marshall'd objects.
969
+ # array of indices, indicating which fields hold Marshall'd values.
970
+ @packer.write_array_header(3)
971
+ @packer.write(qualified_tabname.to_s)
972
+ # The second element, wire_tuple, is an array. We will write it one
973
+ # element at a time:
974
+ @packer.write_array_header(t.length)
975
+ @packer.flush
963
976
  marshall_indexes = []
964
- wire_tuple = Array.new(t.length)
965
- t.each_with_index do |f, i|
977
+ t.each_with_index do |f,i|
978
+ # Performance optimization for cases where we know that we can't
979
+ # marshal the field using MsgPack:
966
980
  if [Bud::Lattice, Class].any?{|t| f.class <= t}
967
981
  marshall_indexes << i
968
- wire_tuple[i] = Marshal.dump(f)
982
+ @wire_buf << Marshal.dump(f).to_msgpack
969
983
  else
970
- wire_tuple[i] = f
984
+ begin
985
+ @wire_buf << f.to_msgpack
986
+ rescue NoMethodError
987
+ # If MsgPack can't marshal the field, fall back to Marshal.
988
+ # This handles fields that contain nested non-MsgPack-able
989
+ # objects (in these cases, the entire field is Marshal'd.)
990
+ marshall_indexes << i
991
+ @wire_buf << Marshal.dump(f).to_msgpack
992
+ end
971
993
  end
972
994
  end
973
- wire_str = [qualified_tabname.to_s, wire_tuple, marshall_indexes].to_msgpack
974
- toplevel.dsock.send_datagram(wire_str, the_locspec[0], the_locspec[1])
995
+ @packer.write(marshall_indexes)
996
+ @packer.flush
997
+ toplevel.dsock.send_datagram(@wire_buf.string,
998
+ the_locspec[0], the_locspec[1])
999
+
1000
+ # Reset output buffer
1001
+ @wire_buf.rewind
1002
+ @wire_buf.truncate(0)
975
1003
  end
976
1004
  @pending.clear
977
1005
  end
@@ -1015,45 +1043,28 @@ module Bud
1015
1043
  end
1016
1044
 
1017
1045
  superator "<+" do |o|
1018
- raise Bud::Error, "illegal use of <+ with channel '#{@tabname}' on left"
1046
+ raise Bud::CompileError, "illegal use of <+ with channel '#{@tabname}' on left"
1019
1047
  end
1020
1048
 
1021
1049
  undef merge
1022
1050
 
1023
1051
  def <=(o)
1024
- raise Bud::Error, "illegal use of <= with channel '#{@tabname}' on left"
1052
+ raise Bud::CompileError, "illegal use of <= with channel '#{@tabname}' on left"
1025
1053
  end
1026
1054
  end
1027
1055
 
1028
1056
  class BudTerminal < BudScratch # :nodoc: all
1029
- def initialize(name, given_schema, bud_instance, prompt=false) # :nodoc: all
1030
- super(name, bud_instance, given_schema)
1057
+ def initialize(name, bud_instance, prompt=false) # :nodoc: all
1058
+ super(name, bud_instance, [:line])
1031
1059
  @prompt = prompt
1032
1060
  end
1033
1061
 
1034
1062
  public
1035
1063
  def start_stdin_reader # :nodoc: all
1036
- # XXX: Ugly hack. Rather than sending terminal data to EM via UDP,
1037
- # we should add the terminal file descriptor to the EM event loop.
1038
- @reader = Thread.new do
1064
+ Thread.new do
1039
1065
  begin
1040
- toplevel = @bud_instance.toplevel
1041
1066
  while true
1042
- out_io = get_out_io
1043
- out_io.print("#{tabname} > ") if @prompt
1044
-
1045
- in_io = toplevel.options[:stdin]
1046
- s = in_io.gets
1047
- break if s.nil? # Hit EOF
1048
- s = s.chomp if s
1049
- tup = [s]
1050
-
1051
- ip = toplevel.ip
1052
- port = toplevel.port
1053
- EventMachine::schedule do
1054
- socket = EventMachine::open_datagram_socket("127.0.0.1", 0)
1055
- socket.send_datagram([tabname, tup, []].to_msgpack, ip, port)
1056
- end
1067
+ break unless read_line
1057
1068
  end
1058
1069
  rescue Exception
1059
1070
  puts "terminal reader thread failed: #{$!}"
@@ -1063,13 +1074,34 @@ module Bud
1063
1074
  end
1064
1075
  end
1065
1076
 
1077
+ # XXX: Ugly hack. Rather than sending terminal data to EM via UDP, we should
1078
+ # add the terminal file descriptor to the EM event loop.
1079
+ private
1080
+ def read_line
1081
+ toplevel = @bud_instance.toplevel
1082
+ if @prompt
1083
+ get_out_io.print("#{tabname} > ")
1084
+ end
1085
+
1086
+ in_io = toplevel.options[:stdin]
1087
+ input_str = in_io.gets
1088
+ return false if input_str.nil? # Hit EOF
1089
+ input_str.chomp!
1090
+
1091
+ EventMachine::schedule do
1092
+ socket = EventMachine::open_datagram_socket("127.0.0.1", 0)
1093
+ socket.send_datagram([tabname, [input_str], []].to_msgpack,
1094
+ toplevel.ip, toplevel.port)
1095
+ end
1096
+
1097
+ return true
1098
+ end
1099
+
1066
1100
  public
1067
1101
  def flush #:nodoc: all
1068
1102
  out_io = get_out_io
1069
- @pending.each_value do |p|
1070
- out_io.puts p[0]
1071
- out_io.flush
1072
- end
1103
+ @pending.each_value {|p| out_io.puts p[0]}
1104
+ out_io.flush
1073
1105
  @pending.clear
1074
1106
  end
1075
1107
 
@@ -1090,7 +1122,6 @@ module Bud
1090
1122
  @tick_delta.clear
1091
1123
  end
1092
1124
  @invalidated = true # channels and terminals are always invalidated.
1093
- raise Bud::Error, "orphaned pending tuples in terminal" unless @pending.empty?
1094
1125
  end
1095
1126
 
1096
1127
  public
@@ -1101,7 +1132,11 @@ module Bud
1101
1132
 
1102
1133
  public
1103
1134
  def <=(o) #:nodoc: all
1104
- raise Bud::Error, "illegal use of <= with terminal '#{@tabname}' on left"
1135
+ raise Bud::CompileError, "illegal use of <= with terminal '#{@tabname}' on left"
1136
+ end
1137
+
1138
+ superator "<+" do |o|
1139
+ raise Bud::CompileError, "illegal use of <+ with terminal '#{@tabname}' on left"
1105
1140
  end
1106
1141
 
1107
1142
  superator "<~" do |o|
@@ -1121,26 +1156,28 @@ module Bud
1121
1156
  def get_out_io
1122
1157
  rv = @bud_instance.toplevel.options[:stdout]
1123
1158
  rv ||= $stdout
1124
- raise Bud::Error, "attempting to write to terminal #{tabname} that was already closed" if rv.closed?
1159
+ if rv.closed?
1160
+ raise Bud::Error, "attempt to write to closed terminal '#{tabname}'"
1161
+ end
1125
1162
  rv
1126
1163
  end
1127
1164
  end
1128
1165
 
1129
1166
  class BudPeriodic < BudScratch # :nodoc: all
1130
1167
  def <=(o)
1131
- raise Bud::Error, "illegal use of <= with periodic '#{tabname}' on left"
1168
+ raise Bud::CompileError, "illegal use of <= with periodic '#{tabname}' on left"
1132
1169
  end
1133
1170
 
1134
1171
  superator "<~" do |o|
1135
- raise Bud::Error, "illegal use of <~ with periodic '#{tabname}' on left"
1172
+ raise Bud::CompileError, "illegal use of <~ with periodic '#{tabname}' on left"
1136
1173
  end
1137
1174
 
1138
1175
  superator "<-" do |o|
1139
- raise Bud::Error, "illegal use of <- with periodic '#{tabname}' on left"
1176
+ raise Bud::CompileError, "illegal use of <- with periodic '#{tabname}' on left"
1140
1177
  end
1141
1178
 
1142
1179
  superator "<+" do |o|
1143
- raise Bud::Error, "illegal use of <+ with periodic '#{tabname}' on left"
1180
+ raise Bud::CompileError, "illegal use of <+ with periodic '#{tabname}' on left"
1144
1181
  end
1145
1182
 
1146
1183
  def tick
@@ -1272,11 +1309,11 @@ module Bud
1272
1309
 
1273
1310
  class BudReadOnly < BudCollection # :nodoc: all
1274
1311
  superator "<+" do |o|
1275
- raise CompileError, "illegal use of <+ with read-only collection '#{@tabname}' on left"
1312
+ raise Bud::CompileError, "illegal use of <+ with read-only collection '#{@tabname}' on left"
1276
1313
  end
1277
1314
  public
1278
1315
  def merge(o) #:nodoc: all
1279
- raise CompileError, "illegal use of <= with read-only collection '#{@tabname}' on left"
1316
+ raise Bud::CompileError, "illegal use of <= with read-only collection '#{@tabname}' on left"
1280
1317
  end
1281
1318
  public
1282
1319
  def invalidate_cache