flor 0.15.0 → 0.16.0

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.
Files changed (117) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +14 -1
  3. data/CREDITS.md +1 -0
  4. data/LICENSE.txt +1 -1
  5. data/Makefile +6 -2
  6. data/README.md +2 -1
  7. data/flor.gemspec +12 -2
  8. data/lib/flor.rb +3 -3
  9. data/lib/flor/colours.rb +1 -1
  10. data/lib/flor/conf.rb +3 -4
  11. data/lib/flor/core/executor.rb +31 -61
  12. data/lib/flor/core/node.rb +213 -96
  13. data/lib/flor/core/procedure.rb +194 -75
  14. data/lib/flor/core/texecutor.rb +6 -7
  15. data/lib/flor/djan.rb +41 -22
  16. data/lib/flor/flor.rb +137 -42
  17. data/lib/flor/id.rb +77 -59
  18. data/lib/flor/log.rb +43 -22
  19. data/lib/flor/migrations/0001_tables.rb +7 -7
  20. data/lib/flor/parser.rb +271 -74
  21. data/lib/flor/pcore/_apply.rb +108 -0
  22. data/lib/flor/pcore/_atom.rb +2 -4
  23. data/lib/flor/pcore/_att.rb +54 -37
  24. data/lib/flor/pcore/_dmute.rb +18 -0
  25. data/lib/flor/pcore/_dol.rb +17 -0
  26. data/lib/flor/pcore/_dqs.rb +35 -0
  27. data/lib/flor/pcore/_head.rb +25 -0
  28. data/lib/flor/pcore/_obj.rb +1 -3
  29. data/lib/flor/pcore/_pat_guard.rb +1 -1
  30. data/lib/flor/pcore/_pat_obj.rb +11 -3
  31. data/lib/flor/pcore/_pat_regex.rb +16 -2
  32. data/lib/flor/pcore/_ref.rb +51 -0
  33. data/lib/flor/pcore/_rxs.rb +27 -0
  34. data/lib/flor/pcore/_val.rb +11 -6
  35. data/lib/flor/pcore/{logo.rb → andor.rb} +4 -6
  36. data/lib/flor/pcore/apply.rb +72 -2
  37. data/lib/flor/pcore/arith.rb +16 -4
  38. data/lib/flor/pcore/array_qmark.rb +100 -0
  39. data/lib/flor/pcore/break.rb +1 -2
  40. data/lib/flor/pcore/case.rb +1 -1
  41. data/lib/flor/pcore/cmp.rb +3 -2
  42. data/lib/flor/pcore/collect.rb +2 -2
  43. data/lib/flor/pcore/cond.rb +19 -1
  44. data/lib/flor/pcore/cursor.rb +12 -11
  45. data/lib/flor/pcore/define.rb +30 -4
  46. data/lib/flor/pcore/do_return.rb +3 -0
  47. data/lib/flor/pcore/flatten.rb +39 -0
  48. data/lib/flor/pcore/if.rb +15 -5
  49. data/lib/flor/pcore/includes.rb +5 -2
  50. data/lib/flor/pcore/inject.rb +1 -1
  51. data/lib/flor/pcore/iterator.rb +28 -18
  52. data/lib/flor/pcore/keys.rb +2 -2
  53. data/lib/flor/pcore/map.rb +19 -1
  54. data/lib/flor/pcore/match.rb +2 -2
  55. data/lib/flor/pcore/matchr.rb +18 -5
  56. data/lib/flor/pcore/max.rb +51 -0
  57. data/lib/flor/pcore/merge.rb +134 -0
  58. data/lib/flor/pcore/move.rb +1 -1
  59. data/lib/flor/pcore/noret.rb +1 -1
  60. data/lib/flor/pcore/not.rb +15 -1
  61. data/lib/flor/pcore/on.rb +11 -0
  62. data/lib/flor/pcore/on_cancel.rb +5 -1
  63. data/lib/flor/pcore/on_error.rb +69 -4
  64. data/lib/flor/pcore/push.rb +4 -9
  65. data/lib/flor/pcore/range.rb +5 -5
  66. data/lib/flor/pcore/reduce.rb +5 -18
  67. data/lib/flor/pcore/return.rb +26 -0
  68. data/lib/flor/pcore/reverse.rb +4 -0
  69. data/lib/flor/pcore/sequence.rb +8 -1
  70. data/lib/flor/pcore/set.rb +74 -15
  71. data/lib/flor/pcore/shuffle.rb +71 -0
  72. data/lib/flor/pcore/slice.rb +137 -0
  73. data/lib/flor/pcore/sort.rb +244 -0
  74. data/lib/flor/pcore/sort_by.rb +67 -0
  75. data/lib/flor/pcore/split.rb +39 -0
  76. data/lib/flor/pcore/stall.rb +1 -1
  77. data/lib/flor/pcore/strings.rb +123 -0
  78. data/lib/flor/pcore/timestamp.rb +34 -0
  79. data/lib/flor/pcore/to_array.rb +2 -3
  80. data/lib/flor/pcore/twig.rb +1 -1
  81. data/lib/flor/pcore/type_of.rb +37 -0
  82. data/lib/flor/pcore/until.rb +3 -3
  83. data/lib/flor/punit/cancel.rb +3 -3
  84. data/lib/flor/punit/ccollect.rb +29 -0
  85. data/lib/flor/punit/cmap.rb +76 -20
  86. data/lib/flor/punit/concurrence.rb +440 -33
  87. data/lib/flor/punit/cron.rb +1 -1
  88. data/lib/flor/punit/every.rb +1 -1
  89. data/lib/flor/punit/graft.rb +2 -3
  90. data/lib/flor/punit/on_timeout.rb +5 -1
  91. data/lib/flor/punit/part.rb +63 -0
  92. data/lib/flor/punit/schedule.rb +1 -1
  93. data/lib/flor/punit/task.rb +52 -10
  94. data/lib/flor/punit/trap.rb +4 -5
  95. data/lib/flor/tools/shell.rb +37 -18
  96. data/lib/flor/unit/caller.rb +23 -11
  97. data/lib/flor/unit/executor.rb +33 -12
  98. data/lib/flor/unit/ganger.rb +10 -1
  99. data/lib/flor/unit/hook.rb +2 -1
  100. data/lib/flor/unit/hooker.rb +13 -2
  101. data/lib/flor/unit/loader.rb +7 -7
  102. data/lib/flor/unit/logger.rb +15 -17
  103. data/lib/flor/unit/models.rb +4 -2
  104. data/lib/flor/unit/models/execution.rb +83 -38
  105. data/lib/flor/unit/models/message.rb +16 -0
  106. data/lib/flor/unit/models/pointer.rb +24 -0
  107. data/lib/flor/unit/models/timer.rb +25 -4
  108. data/lib/flor/unit/models/trace.rb +14 -0
  109. data/lib/flor/unit/models/trap.rb +39 -14
  110. data/lib/flor/unit/scheduler.rb +11 -7
  111. data/lib/flor/unit/storage.rb +55 -39
  112. data/lib/flor/unit/taskers.rb +17 -14
  113. data/lib/flor/unit/waiter.rb +4 -3
  114. metadata +40 -10
  115. data/lib/flor/changes.rb +0 -26
  116. data/lib/flor/dollar.rb +0 -224
  117. data/lib/flor/unit/hooks.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 5d8fca99889bde91b7433d98d674f44c810c041421ce61eef1857e80930e8cef
4
- data.tar.gz: 7a06654dbe17ac06aa3afeab0a04b9958851bdaf393df0d48f994dae4681c072
2
+ SHA1:
3
+ metadata.gz: b973449e80aa849aee7d3fade7ab13fe57a0b6a1
4
+ data.tar.gz: a09d4a0b88d453b42742bb8814d5cee1f957c2c2
5
5
  SHA512:
6
- metadata.gz: 0a17e80b8bf6207bd3688f2c57172a51ac471c5f3beaf28803ff8ce41587dc6b181b5295b041dbfa586e6556ee045be56553164e6b09183745c0cfd2562d8c0c
7
- data.tar.gz: fad82fa8619af8623b6312d6a4f234f5433d71edcbd05964367c8cde547be357f08d77e9c0e99078f2c71cbf74bfbf7691cae62025f53ce7537ad91cb0ef4d74
6
+ metadata.gz: 139a8cf68527edcdff12137a9ac831eee6fb9867a49ed9fe24d462efce7f3d53f9396de2302b449f963c1e74fe4e67b5590f04ad5605a6996bb35e6e0f7015ad
7
+ data.tar.gz: 9de9e3bb4f12f2cb1b48ae0aa4d024ce4ce557b380d5b476c03dae7a7db63480ec041269702102a40165a3ed8ecb290d7b2c77299f999fdf605071976c2f99ea
@@ -1,5 +1,18 @@
1
1
 
2
- # flor CHANGELOG.md
2
+ # CHANGELOG.md
3
+
4
+
5
+ ## flor 1.0.0 not yet released
6
+
7
+
8
+ ## flor 0.16.0 released 2019-02-04
9
+
10
+ - Many many improvements
11
+ - Include "undense" work ("_ref" and friends)
12
+ - Include "undense" work (killing the dollar subsystem)
13
+ - Fix dereserving delayed messages
14
+ - allow for cancel behaviour when "cursor", "sequence", and "until"
15
+ node_status flavour is "on-error"
3
16
 
4
17
 
5
18
  ## flor 0.15.0 released 2018-06-15
data/CREDITS.md CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  ## Contributors
5
5
 
6
+ * Jeffrey Hicks - https://github.com/jrhicks
6
7
  * David Verrier - https://github.com/dverrier
7
8
  * Tsunehisa Doi - https://github.com/dmicky0419
8
9
  * Jean-François Rioux - https://github.com/jfrioux
@@ -1,5 +1,5 @@
1
1
 
2
- Copyright (c) 2015-2018, John Mettraux, jmettraux+flor@gmail.com
2
+ Copyright (c) 2015-2019, John Mettraux, jmettraux+flor@gmail.com
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to deal
data/Makefile CHANGED
@@ -13,12 +13,15 @@ cl: count_lines
13
13
 
14
14
  gemspec_validate:
15
15
  @echo "---"
16
- ruby -e "s = eval(File.read(Dir['*.gemspec'].first)); s.validate"
16
+ ruby -e "s = eval(File.read(Dir['*.gemspec'].first)); p s.validate"
17
17
  @echo "---"
18
18
 
19
19
  name: gemspec_validate
20
20
  @echo "$(NAME) $(VERSION)"
21
21
 
22
+ cw:
23
+ find lib -name "*.rb" -exec ruby -cw {} \; | grep lib
24
+
22
25
  syncver:
23
26
  sed -E -i '' "s/VERSION = ['0-9.]+/VERSION = '$(shell grep -E "$(NAME) ([0-9.]+)" CHANGELOG.md | head -1 | sed -E 's/[^0-9\.]//g')'/" lib/$(NAME).rb
24
27
  bundle install
@@ -81,5 +84,6 @@ cleanshell:
81
84
  rm -fR envs/shell/var/tasks/*
82
85
  rm -f .log.txt
83
86
 
84
- .PHONY: doc shell cleanshell
87
+ .PHONY: \
88
+ count_lines gemspec_validate name cw build push spec doc shell cleanshell
85
89
 
data/README.md CHANGED
@@ -32,8 +32,9 @@ See [doc/](doc/).
32
32
 
33
33
  ## blog posts and presentations
34
34
 
35
+ * [the flor language](http://jmettraux.skepti.ch/20180927.html?t=the_flor_language) - on the flor workflow definition language itself
35
36
  * [Flor, hubristic interpreter](http://rubykaigi.org/2017/presentations/jmettraux.html) - RubyKaigi 2017, Hiroshima - presentation
36
- * [flor design 0](http://jmettraux.skepti.ch/20171021.html?t=flor_design_0) - running a simple execution, what happens - blog post
37
+ * [flor design 0](http://jmettraux.skepti.ch/20171021.html?t=flor_design_0&f=readme) - running a simple execution, what happens - blog post
37
38
  * [flor, branch to branch](https://speakerdeck.com/jmettraux/flor-branch-to-branch) - q1 2017 - very dry deck
38
39
  * [flor 2017](https://speakerdeck.com/jmettraux/flor-2017) - q1 2017 - very dry deck
39
40
 
@@ -15,6 +15,16 @@ Gem::Specification.new do |s|
15
15
  s.license = 'MIT'
16
16
  s.summary = 'A Ruby workflow engine'
17
17
 
18
+ s.metadata = {
19
+ 'changelog_uri' => s.homepage + '/flor/blob/master/CHANGELOG.md',
20
+ 'documentation_uri' => s.homepage + '/flor/tree/master/doc',
21
+ 'bug_tracker_uri' => s.homepage + '/flor/issues',
22
+ 'mailing_list_uri' => 'https://groups.google.com/forum/#!forum/floraison',
23
+ 'homepage_uri' => s.homepage + '/flor',
24
+ 'source_code_uri' => s.homepage + '/flor',
25
+ #'wiki_uri' => s.homepage + '/flor/wiki',
26
+ }
27
+
18
28
  s.description = %{
19
29
  A Ruby workflow engine (ruote next generation)
20
30
  }.strip
@@ -31,8 +41,8 @@ A Ruby workflow engine (ruote next generation)
31
41
  s.add_runtime_dependency 'munemo', '~> 1.0', '>= 1.0.1'
32
42
  s.add_runtime_dependency 'raabro', '~> 1.1', '>= 1.1.5'
33
43
  #s.add_runtime_dependency 'rufus-lru', '~> 1.1'
34
- s.add_runtime_dependency 'fugit', '~> 1.1'
35
- s.add_runtime_dependency 'dense', '~> 1.1', '>= 1.1.1'
44
+ s.add_runtime_dependency 'fugit', '~> 1.1', '>= 1.1.8'
45
+ s.add_runtime_dependency 'dense', '~> 1.1', '>= 1.1.6'
36
46
 
37
47
  s.add_runtime_dependency 'sequel', '~> 4'
38
48
 
@@ -5,6 +5,7 @@ require 'logger'
5
5
  require 'thread'
6
6
  require 'digest'
7
7
  require 'socket'
8
+ require 'forwardable'
8
9
 
9
10
  require 'munemo'
10
11
  require 'raabro'
@@ -13,7 +14,8 @@ require 'dense'
13
14
 
14
15
  module Flor
15
16
 
16
- VERSION = '0.15.0'
17
+ VERSION = '0.16.0'
18
+ #VERSION = '1.0.0'
17
19
  end
18
20
 
19
21
  require 'flor/colours'
@@ -22,11 +24,9 @@ require 'flor/djan'
22
24
  require 'flor/id'
23
25
  require 'flor/log'
24
26
  require 'flor/flor'
25
- require 'flor/dollar'
26
27
  require 'flor/errors'
27
28
  require 'flor/parser'
28
29
  require 'flor/conf'
29
- require 'flor/changes'
30
30
  require 'flor/to_string'
31
31
 
32
32
  require 'flor/core'
@@ -28,7 +28,7 @@ module Flor
28
28
  if v.match(/\A\d/)
29
29
  class_eval(%{
30
30
  def #{k}(s=nil)
31
- s ? "[#{v}m" + s + "": "[#{v}m"
31
+ s ? "[#{v}m" + s + "" : "[#{v}m"
32
32
  end })
33
33
  else
34
34
  class_eval(
@@ -114,13 +114,12 @@ module Flor
114
114
  a = plus - minus
115
115
 
116
116
  h =
117
- a.inject({}) { |h, kv|
117
+ a.inject({}) { |hh, kv|
118
118
  k, v = kv.split(':')
119
119
  k = 'sto' if k == 'db'
120
120
  k = "log_#{k}" if LOG_ALL_KEYS.include?(k)
121
- h[k] = v ? JSON.parse(v) : true
122
- h
123
- }
121
+ hh[k] = v ? JSON.parse(v) : true
122
+ hh }
124
123
  LOG_ALL_KEYS.each { |k| h["log_#{k}"] = 1 } if h['log_all']
125
124
  LOG_DBG_KEYS.each { |k| h["log_#{k}"] = 1 } if h['log_dbg']
126
125
 
@@ -15,6 +15,8 @@ module Flor
15
15
 
16
16
  @hooks = hooks # raw hooks if any, fresh from the loader
17
17
  @traps = traps # array of Trap instances
18
+
19
+ @htraps = nil
18
20
  end
19
21
 
20
22
  def conf; @unit.conf; end
@@ -144,6 +146,10 @@ module Flor
144
146
  # cnid: closure nid
145
147
  # dbg: used to debug messages (useful @node['dbg'] when 'receive')
146
148
 
149
+ if oeh = message['on_error_handler']
150
+ node['on_error'] = [ [ [ '*' ], oeh ] ]
151
+ end
152
+
147
153
  @execution['nodes'][nid] = node
148
154
  end
149
155
 
@@ -158,9 +164,7 @@ module Flor
158
164
  make_node(message) :
159
165
  @execution['nodes'][nid]
160
166
 
161
- return unless node
162
-
163
- return if node['heat']
167
+ return if node.nil? || node['heat']
164
168
 
165
169
  n = Flor::Node.new(self, node, message)
166
170
 
@@ -173,34 +177,33 @@ module Flor
173
177
  node['tree'] = mt if mt && (mt != nt)
174
178
  tree = node['tree'] || nt
175
179
 
176
- t0 = tree[0]
177
- t0 = (t0.is_a?(Array) && t0[0] == '_dqs') ? n.expand(t0[1]) : t0
178
-
179
- node['heat0'] = tree[0]
180
+ node['heat0'] = t0 = tree[0]
180
181
  node['heat'] = heat = n.deref(t0)
181
- node['heap'] = heap = n.reheap(tree, heat)
182
182
 
183
- # "exceptions"
183
+ if heat == nil && ! message['accept_symbol']
184
184
 
185
- if heat == nil && tree[0].index('.') && tree[1].empty?
186
- #
187
- # a field reference that points to nothing returns null
185
+ node['heat'] = '(none)'
188
186
 
189
- node['heat0'] = '_nul'
190
- node['heat'] = '_nul'
191
- node['heap'] = '_nul'
187
+ fail FlorError.new("cannot find #{t0.inspect}", n) if tree[1].empty?
188
+ fail FlorError.new("don't know how to apply #{t0.inspect}", n)
189
+ # TODO how about _ref and letting that procedure fail
190
+ end
192
191
 
193
- elsif message['accept_symbol'] && heat == nil
192
+ node['heap'] = heap = n.reheap(tree, heat)
193
+
194
+ # "exceptions"
195
+
196
+ if heat == nil #&& message['accept_symbol']
194
197
  #
195
198
  # tag: et al
196
199
 
197
- node['tree'] = message['tree'] = t = [ '_dqs', tree[0], tree[2] ]
200
+ node['tree'] = message['tree'] = t = [ '_sqs', tree[0], tree[2] ]
198
201
 
199
202
  node['heat0'] = t[0]
200
203
  node['heat'] = h = n.deref(t[0])
201
204
  node['heap'] = n.reheap(t, h)
202
205
 
203
- elsif heap == 'task' && heat[0] == '_task'
206
+ elsif heap == 'task' && heat[0] == '_tasker'
204
207
  #
205
208
  # rewrite `alpha` into `task alpha`
206
209
 
@@ -211,7 +214,7 @@ module Flor
211
214
  message['tree'][0] =
212
215
  'task'
213
216
  message['tree'][1].unshift(
214
- [ '_att', [ [ '_sqs', heat[1]['task'], l ] ], l ])
217
+ [ '_att', [ [ '_sqs', heat[1]['tasker'], l ] ], l ])
215
218
  end
216
219
  end
217
220
 
@@ -222,16 +225,7 @@ module Flor
222
225
 
223
226
  def apply(node, message)
224
227
 
225
- heap =
226
- if node['heat']
227
- node['heap']
228
- else
229
- node['failure'] ? '_err' : nil
230
- end
231
-
232
- return error_reply(
233
- node, message, "don't know how to apply #{node['heat0'].inspect}"
234
- ) if heap == nil
228
+ heap = node['heap']
235
229
 
236
230
  heac = Flor::Procedure[heap]
237
231
  fail NameError.new("unknown procedure #{heap.inspect}") unless heac
@@ -283,11 +277,11 @@ module Flor
283
277
 
284
278
  def leave_node(message)
285
279
 
280
+ return [] if %w[ flank part ].include?(message['flavour'])
281
+
286
282
  fnid = message['from']; return [] unless fnid
287
283
  fnode = @execution['nodes'][fnid]; return [] unless fnode
288
284
 
289
- return [] if message['flavour'] == 'flank'
290
-
291
285
  remove_node(message, fnode) +
292
286
  leave_tags(message, fnode)
293
287
  end
@@ -380,36 +374,6 @@ module Flor
380
374
  [ m ]
381
375
  end
382
376
 
383
- def task(message)
384
-
385
- return error_reply(
386
- node(message['nid']),
387
- message,
388
- "don't know how to apply #{message['tasker'].inspect}"
389
- ) if message['routed'] == false
390
-
391
- @execution['tasks'][message['nid']] =
392
- { 'tasker' => message['tasker'], 'name' => message['taskname'] }
393
- #
394
- # FIXME is it in use???
395
-
396
- @unit.ganger.task(self, message)
397
- end
398
- alias detask task
399
-
400
- def return(message)
401
-
402
- @execution['tasks'].delete(message['nid'])
403
- #
404
- # FIXME is it in use???
405
-
406
- [ { 'point' => 'receive',
407
- 'exid' => message['exid'],
408
- 'nid' => message['nid'],
409
- 'payload' => message['payload'],
410
- 'tasker' => message['tasker'] } ]
411
- end
412
-
413
377
  def cancel(message)
414
378
 
415
379
  n = @execution['nodes'][message['nid']]
@@ -444,6 +408,11 @@ module Flor
444
408
 
445
409
  def process(message)
446
410
 
411
+ fail ArgumentError.new("incoming message has non nil or Hash payload") \
412
+ unless message['payload'] == nil || message['payload'].is_a?(Hash)
413
+ #
414
+ # weed out messages with non-conforming payloads
415
+
447
416
  begin
448
417
 
449
418
  message['m'] = counter_next('msgs') # number messages
@@ -516,6 +485,7 @@ module Flor
516
485
  # with its 'on_error' turned on.
517
486
  #
518
487
  oep.trigger_on_error
488
+ #
519
489
  else
520
490
  #
521
491
  # Simply log and don't add further messages ([]) to execute
@@ -2,10 +2,12 @@
2
2
  class Flor::Node
3
3
 
4
4
  class Payload
5
+
5
6
  def initialize(node, type=:node)
6
7
  @node = node
7
8
  @type = type
8
9
  end
10
+
9
11
  def has_key?(k)
10
12
  current.has_key?(k)
11
13
  end
@@ -33,7 +35,16 @@ class Flor::Node
33
35
  def merge(h)
34
36
  current.merge(h)
35
37
  end
38
+
39
+ def ret
40
+ self['ret']
41
+ end
42
+ def ret=(v)
43
+ self['ret'] = v
44
+ end
45
+
36
46
  protected
47
+
37
48
  def container
38
49
  @type == :node ? @node.h : @node.message
39
50
  end
@@ -71,6 +82,8 @@ class Flor::Node
71
82
  def nid; @node['nid']; end
72
83
  def parent; @node['parent']; end
73
84
 
85
+ def child_id; Flor.child_id(@node['nid']); end
86
+
74
87
  def domain; Flor.domain(@execution['exid']); end
75
88
 
76
89
  def point; @message['point']; end
@@ -78,6 +91,7 @@ class Flor::Node
78
91
 
79
92
  def cnodes; @node['cnodes']; end
80
93
  def cnodes_any?; cnodes && cnodes.any?; end
94
+ def cnodes_empty?; cnodes.nil? || cnodes.empty?; end
81
95
 
82
96
  def payload
83
97
  @message_payload ||= Payload.new(self, :message)
@@ -106,6 +120,10 @@ class Flor::Node
106
120
  Flor.dup(node_payload['ret'])
107
121
  end
108
122
 
123
+ def payload_ret
124
+ message['payload']['ret']
125
+ end
126
+
109
127
  def message_or_node_payload
110
128
  payload.current ? payload : node_payload
111
129
  end
@@ -151,89 +169,86 @@ class Flor::Node
151
169
  #
152
170
  # that might be the way...
153
171
 
154
- def lookup(name, silence_index_error=false)
172
+ def lookup_value(path)
173
+
174
+ original_path = path
155
175
 
156
- cat, mod, key_and_path = key_split(name)
157
- key, pth = key_and_path.split('.', 2)
176
+ path =
177
+ case path
178
+ when '*' then [ path ]
179
+ when String then Dense::Path.make(path).to_a
180
+ else path
181
+ end
158
182
 
159
- if [ cat, mod, key ] == [ 'v', '', 'node' ]
160
- lookup_in_node(pth)
161
- elsif cat == 'v'
162
- lookup_var(@node, mod, key, pth)
163
- elsif cat == 't'
164
- lookup_tag(mod, key)
183
+ path.unshift('v') \
184
+ if path.length < 2
185
+
186
+ case path.first
187
+ when /\Af(?:ld|ield)?\z/
188
+ lookup_field(nil, path[1..-1]) # mod -> nil...
189
+ when /\At(?:ag)?\z/
190
+ lookup_tag(nil, path[1])
191
+ when /\A([lgd]?)v(?:ar|ariable)?\z/
192
+ return @message['__head'][1] if path[1] == '__head'
193
+ lookup_var(@node, $1, path[1], path[2..-1])
194
+ when 'node'
195
+ lookup_in_node(path[1..-1])
196
+ when 'exe', 'execution'
197
+ lookup_in_execution(path[1..-1])
165
198
  else
166
- lookup_field(mod, key_and_path)
199
+ lookup_var(@node, '', path[0], path[1..-1])
167
200
  end
168
201
 
169
- rescue KeyError, TypeError
170
-
171
- raise unless silence_index_error
172
- nil
173
- end
174
-
175
- class Expander < Flor::Dollar
176
-
177
- def initialize(n); @node = n; end
178
-
179
- def lookup(k)
202
+ rescue KeyError => ke
180
203
 
181
- return @node.nid if k == 'nid'
182
- return @node.exid if k == 'exid'
183
- return Flor.domain(@node.exid) if k == 'domain'
184
- return Flor.tstamp if k == 'tstamp'
204
+ class << ke; attr_accessor :original_path, :work_path; end
205
+ ke.original_path = original_path
206
+ ke.work_path = path
185
207
 
186
- r = @node.lookup(k, true)
187
- r.is_a?(Symbol) ? nil : r
188
- end
208
+ raise
189
209
  end
190
210
 
191
- def expand(s)
211
+ # Returns the referenced tree.
212
+ # Returns nil if not found.
213
+ #
214
+ def deref(s)
192
215
 
193
- return s unless s.is_a?(String)
216
+ v = lookup_value(s)
194
217
 
195
- Expander.new(self).expand(s)
196
- end
218
+ if Flor.is_tree?(v)
197
219
 
198
- def deref(o)
220
+ ref =
221
+ case v[0]
222
+ when '_func' then true
223
+ when '_proc' then v[1]['proc'] != s
224
+ when '_tasker' then v[1]['tasker'] != s
225
+ else false
226
+ end
199
227
 
200
- return o unless o.is_a?(String)
228
+ v[1]['oref'] ||= v[1]['ref'] if ref && v[1]['ref']
229
+ v[1]['ref'] = s if ref
201
230
 
202
- v = lookup(o)
231
+ v
203
232
 
204
- return v unless Flor.is_tree?(v)
205
- return v unless v[1].is_a?(Hash)
206
-
207
- return v unless %w[ _proc _task _func ].include?(v[0])
233
+ else
208
234
 
209
- ref =
210
- case v[0]
211
- when '_func' then true
212
- when '_proc' then v[1]['proc'] != o
213
- when '_task' then v[1]['task'] != o
214
- else false
215
- end
235
+ [ '_val', v, tree[2] ]
236
+ end
216
237
 
217
- v[1]['oref'] ||= v[1]['ref'] if ref && v[1]['ref']
218
- v[1]['ref'] = o if ref
238
+ rescue KeyError => ke
219
239
 
220
- v
240
+ nil
221
241
  end
222
242
 
223
243
  def reheap(tree, heat)
224
244
 
225
- if ! heat.is_a?(Array)
226
- '_val'
227
- elsif tree && tree[1] == []
228
- '_val'
229
- elsif heat[0] == '_proc'
230
- heat[1]['proc']
231
- elsif heat[0] == '_func'
232
- 'apply'
233
- elsif heat[0] == '_task'
234
- 'task'
235
- else
236
- '_val'
245
+ case
246
+ when ! heat.is_a?(Array) then '_val'
247
+ when tree && tree[1] == [] then '_val'
248
+ when heat[0] == '_proc' then heat[1]['proc']
249
+ when heat[0] == '_func' then 'apply'
250
+ when heat[0] == '_tasker' then 'task'
251
+ else '_val'
237
252
  end
238
253
  end
239
254
 
@@ -247,17 +262,6 @@ class Flor::Node
247
262
  "#{exid}-#{nid}"
248
263
  end
249
264
 
250
- def on_error_parent
251
-
252
- oe = @node['on_error']
253
- return self if oe && oe.any?
254
-
255
- pn = parent_node
256
- return Flor::Node.new(@executor, pn, @message).on_error_parent if pn
257
-
258
- nil
259
- end
260
-
261
265
  def to_procedure_node
262
266
 
263
267
  Flor::Procedure.new(@executor, @node, @message)
@@ -279,6 +283,24 @@ class Flor::Node
279
283
  false
280
284
  end
281
285
 
286
+ def on_error_parent(skip=false)
287
+
288
+ if @node['in_on_error'] # prevent loop when error in on_error:
289
+ skip = true
290
+ end
291
+
292
+ if (@node['on_error'] || []).find { |criteria, _| match_on?(criteria) }
293
+ return self unless skip
294
+ skip = false
295
+ end
296
+
297
+ if pn = parent_node
298
+ return Flor::Node.new(@executor, pn, @message).on_error_parent(skip)
299
+ end
300
+
301
+ nil
302
+ end
303
+
282
304
  protected
283
305
 
284
306
  def subtree(tree, pnid, nid)
@@ -294,7 +316,7 @@ class Flor::Node
294
316
  return nil unless cid
295
317
  # maybe failing would be better
296
318
 
297
- cid.split('_').each { |cid| tree = tree[1][cid.to_i] }
319
+ cid.split('_').each { |id| tree = tree[1][id.to_i] }
298
320
 
299
321
  tree
300
322
  end
@@ -309,7 +331,21 @@ class Flor::Node
309
331
  lookup_tree(node['parent'])
310
332
  end
311
333
 
312
- def is_ancestor_node?(nid, node=@node)
334
+ def parent_node_procedure(node=@node)
335
+
336
+ Flor::Procedure.make(@executor, parent_node(node), @message)
337
+ end
338
+
339
+ # Returns true if the current node has the node identified with nid as
340
+ # an ancestor. Returns false else.
341
+ #
342
+ def is_ancestor_node?(node_or_nid, node=@node)
343
+
344
+ nid = node_or_nid
345
+
346
+ return false unless nid
347
+
348
+ nid = node_or_nid['nid'] unless nid.is_a?(String)
313
349
 
314
350
  return false unless node
315
351
  return true if node['nid'] == nid
@@ -321,9 +357,18 @@ class Flor::Node
321
357
  # @execution['nodes'][node['cnid']]
322
358
  #end
323
359
 
324
- def lookup_in_node(pth)
360
+ def lookup_in_node(path)
325
361
 
326
- Dense.fetch(@node, pth)
362
+ Dense.fetch(@node, path)
363
+ end
364
+
365
+ def lookup_in_execution(path)
366
+
367
+ if path == %w[ domain ]
368
+ Flor.domain(@execution['exid'])
369
+ else
370
+ Dense.fetch(@execution, path)
371
+ end
327
372
  end
328
373
 
329
374
  class PseudoVarContainer < Hash
@@ -336,7 +381,7 @@ class Flor::Node
336
381
  end
337
382
  #
338
383
  PROC_VAR_CONTAINER = PseudoVarContainer.new('proc')
339
- TASKER_VAR_CONTAINER = PseudoVarContainer.new('task')
384
+ TASKER_VAR_CONTAINER = PseudoVarContainer.new('tasker')
340
385
 
341
386
  def escape(k)
342
387
 
@@ -357,19 +402,53 @@ class Flor::Node
357
402
 
358
403
  rescue KeyError => ke
359
404
 
360
- return nil if ke.miss[4].empty?
361
-
362
405
  m = "variable #{ke.miss[3].inspect} not found"
363
406
  m += " at #{Dense::Path.make(ke.miss[1]).to_s.inspect}" if ke.miss[1].any?
364
407
 
365
408
  raise ke.relabel(m)
366
409
 
410
+ rescue IndexError => ie
411
+
412
+ m =
413
+ if ie.miss[1] == [ ie.miss[2] ]
414
+ "variable #{ie.miss[2].inspect} not found"
415
+ else
416
+ pa = Dense::Path.make(ie.miss[1]).to_s.inspect
417
+ ty = Flor.type(ie.miss[2])
418
+ ke = ie.miss[3].inspect
419
+ "variable at #{pa} is a #{ty}, it has no key #{ke}"
420
+ end
421
+
422
+ raise ie.relabel(m)
423
+
367
424
  #rescue TypeError => te # leave as is
368
425
  end
369
426
 
427
+ def var_match?(vs, key)
428
+
429
+ vs.each do |v|
430
+ return true if v == key
431
+ return true if v.is_a?(Regexp) && v =~ key
432
+ # TODO fun call
433
+ end
434
+
435
+ false
436
+ end
437
+
370
438
  def lookup_var_container(node, mod, key)
371
439
 
372
- return lookup_dvar_container(mod, key) if node == nil || mod == 'd'
440
+ return lookup_dvar_container(mod, key) \
441
+ if node == nil || mod == 'd'
442
+
443
+ return lookup_arg_container(key) \
444
+ if mod == '' && %w[ args argv argh ].include?(key)
445
+
446
+ if vwl = node['vwlist']
447
+ return lookup_dvar_container(mod, key) unless var_match?(vwl, key)
448
+ end
449
+ if vbl = node['vblist']
450
+ return lookup_dvar_container(mod, key) if var_match?(vbl, key)
451
+ end
373
452
 
374
453
  pnode = parent_node(node)
375
454
  vars = node['vars']
@@ -413,15 +492,21 @@ class Flor::Node
413
492
  {}
414
493
  end
415
494
 
416
- def lookup_var_name(node, val)
495
+ def lookup_arg_container(key)
417
496
 
418
- return nil unless node
497
+ vars = lookup_var_container(@node, '', 'arguments')
498
+ return {} unless vars
419
499
 
420
- vars = node['vars']
421
- k, _ = vars && vars.find { |k, v| v == val }
422
- return k if k
500
+ args = vars['arguments']
501
+ return {} unless args
423
502
 
424
- lookup_var_name(parent_node(node), val)
503
+ val =
504
+ case key
505
+ when 'args', 'argv' then args.collect(&:last)
506
+ else args.inject({}) { |h, (k, v)| h[k] = v if k; h }
507
+ end
508
+
509
+ { key => val }
425
510
  end
426
511
 
427
512
  def lookup_tag(mod, key)
@@ -432,28 +517,60 @@ class Flor::Node
432
517
  a
433
518
  end
434
519
 
435
- nids.empty? ? [ '_nul', nil, -1 ] : nids
520
+ nids.any? ? nids : nil
436
521
  end
437
522
 
438
523
  def lookup_field(mod, key_and_path)
439
524
 
440
525
  Dense.fetch(payload.current, key_and_path)
526
+ end
441
527
 
442
- rescue IndexError
528
+ # Return true if the current @message matches on the given array of
529
+ # criteria.
530
+ #
531
+ def match_on?(criteria)
443
532
 
444
- nil
533
+ # AND, not OR, hence the true at the bottom
534
+
535
+ criteria
536
+ .each { |c|
537
+ next if c == '*'
538
+ return false unless send("match_on_#{c[0]}?", c) }
539
+
540
+ true
445
541
  end
446
542
 
447
- def key_split(key) # => category, mode, key
543
+ def extract_on_info
544
+
545
+ kla = @message['error']['kla']
546
+ msg = @message['error']['msg']
547
+ la = kla.split('::').last
548
+
549
+ [ kla, la, msg ]
550
+ end
551
+
552
+ def match_on_class?(criterion)
553
+
554
+ c1 = criterion[1]
555
+ kla, la, _ = extract_on_info
556
+
557
+ kla == c1 || la == c1
558
+ end
559
+
560
+ def match_on_string?(criterion)
561
+
562
+ c1 = criterion[1]
563
+ kla, la, msg = extract_on_info
564
+
565
+ msg == c1 || kla == c1 || la == c1
566
+ end
448
567
 
449
- m = key.match(
450
- /\A(?:([lgd]?)((?:v|var|variable)|w|f|fld|field|t|tag)\.)?(.+)\z/)
568
+ def match_on_regex?(criterion)
451
569
 
452
- ca = (m[2] || 'v')[0, 1]
453
- mo = m[1] || ''
454
- ke = m[3]
570
+ c1 = Flor.to_regex(criterion)
571
+ kla, _, msg = extract_on_info
455
572
 
456
- [ ca, mo, ke ]
573
+ msg =~ c1 || kla =~ c1
457
574
  end
458
575
  end
459
576