flor 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/CHANGELOG.md +8 -0
  2. data/lib/flor.rb +1 -1
  3. data/lib/flor/core.rb +7 -0
  4. data/lib/flor/core/executor.rb +43 -8
  5. data/lib/flor/core/node.rb +84 -54
  6. data/lib/flor/core/procedure.rb +36 -19
  7. data/lib/flor/core/texecutor.rb +4 -1
  8. data/lib/flor/deep.rb +43 -51
  9. data/lib/flor/dollar.rb +2 -3
  10. data/lib/flor/flor.rb +38 -9
  11. data/lib/flor/parser.rb +123 -72
  12. data/lib/flor/pcore/_arr.rb +15 -0
  13. data/lib/flor/pcore/_atom.rb +6 -5
  14. data/lib/flor/pcore/_att.rb +9 -4
  15. data/lib/flor/pcore/_obj.rb +28 -34
  16. data/lib/flor/pcore/_pat_.rb +77 -0
  17. data/lib/flor/pcore/_pat_arr.rb +131 -0
  18. data/lib/flor/pcore/_pat_guard.rb +70 -0
  19. data/lib/flor/pcore/_pat_obj.rb +143 -0
  20. data/lib/flor/pcore/_pat_or.rb +46 -0
  21. data/lib/flor/pcore/_val.rb +20 -0
  22. data/lib/flor/pcore/arith.rb +7 -1
  23. data/lib/flor/pcore/case.rb +46 -69
  24. data/lib/flor/pcore/cursor.rb +24 -24
  25. data/lib/flor/pcore/define.rb +5 -1
  26. data/lib/flor/pcore/do_return.rb +32 -0
  27. data/lib/flor/pcore/length.rb +18 -0
  28. data/lib/flor/pcore/logo.rb +47 -0
  29. data/lib/flor/pcore/map.rb +12 -10
  30. data/lib/flor/pcore/match.rb +276 -0
  31. data/lib/flor/pcore/not.rb +13 -0
  32. data/lib/flor/pcore/push.rb +52 -13
  33. data/lib/flor/pcore/range.rb +69 -0
  34. data/lib/flor/pcore/set.rb +82 -24
  35. data/lib/flor/unit/hook.rb +28 -0
  36. data/lib/flor/unit/hooker.rb +5 -0
  37. data/lib/flor/unit/loader.rb +4 -1
  38. data/lib/flor/unit/storage.rb +5 -3
  39. data/lib/flor/unit/waiter.rb +12 -2
  40. data/lib/flor/unit/wlist.rb +4 -3
  41. data/match.md +22 -0
  42. metadata +15 -5
  43. data/lib/flor/pcore/_happly.rb +0 -49
  44. data/lib/flor/pcore/val.rb +0 -16
  45. data/t.txt +0 -4
@@ -2,6 +2,14 @@
2
2
  # flor CHANGELOG.md
3
3
 
4
4
 
5
+ ## flor 0.14.0 released 2017-06-13
6
+
7
+ - Implement "match"
8
+ - Implement "range"
9
+ - Implement "for-each"
10
+ - Merge enhancements by @jfrioux
11
+
12
+
5
13
  ## flor 0.13.0 released 2017-04-24
6
14
 
7
15
  - Simplify "trace" implementation
@@ -12,7 +12,7 @@ require 'raabro'
12
12
 
13
13
  module Flor
14
14
 
15
- VERSION = '0.13.0'
15
+ VERSION = '0.14.0'
16
16
  end
17
17
 
18
18
  require 'flor/colours'
@@ -44,6 +44,13 @@ module Flor
44
44
  pl = opts[:payload] || opts[:fields] || {}
45
45
  vs = opts[:variables] || opts[:vars] || {}
46
46
 
47
+ fail ArgumentError.new(
48
+ "given launch payload should be a Hash, but it's a #{pl.class}"
49
+ ) unless pl.is_a?(Hash)
50
+ fail ArgumentError.new(
51
+ "given launch variables should come in a Hash, but it's a #{vs.class}"
52
+ ) unless vs.is_a?(Hash)
53
+
47
54
  msg =
48
55
  { 'point' => 'execute',
49
56
  'exid' => exid,
@@ -182,18 +182,23 @@ module Flor
182
182
 
183
183
  # "exceptions"
184
184
 
185
- # TODO could those two ifs go upstream (top of this method)
186
- # and thus become smaller
187
- #
188
- if message['accept_symbol'] && node['heat'] == nil
185
+ if heat == nil && tree[0].index('.') && tree[1].empty?
186
+ #
187
+ # a field reference that points to nothing returns null
188
+
189
+ node['heat0'] = '_nul'
190
+ node['heat'] = '_nul'
191
+ node['heap'] = '_nul'
192
+
193
+ elsif message['accept_symbol'] && heat == nil
189
194
  #
190
195
  # tag: et al
191
196
 
192
- tree = node['tree'] = message['tree'] = [ '_dqs', tree[0], tree[2] ]
197
+ node['tree'] = message['tree'] = t = [ '_dqs', tree[0], tree[2] ]
193
198
 
194
- node['heat0'] = tree[0]
195
- node['heat'] = heat = n.deref(tree[0])
196
- node['heap'] = heap = n.reheap(tree, heat)
199
+ node['heat0'] = t[0]
200
+ node['heat'] = h = n.deref(t[0])
201
+ node['heap'] = n.reheap(t, h)
197
202
 
198
203
  elsif heap == 'task' && heat[0] == '_task'
199
204
  #
@@ -296,11 +301,41 @@ module Flor
296
301
  @unit.archive_node(message['exid'], node)
297
302
  # archiving is only active during testing
298
303
 
304
+ #update_parent_node_tree(node)
305
+
299
306
  @execution['nodes'].delete(nid)
300
307
 
301
308
  cancels
302
309
  end
303
310
 
311
+ # This saves the modified trees in the parent when the node is removed
312
+ # it works ok except for 3 (2017-05-9) failing specs.
313
+ #
314
+ # Introducing 3 exceptions for this is not interesting.
315
+ #
316
+ # def update_parent_node_tree(node)
317
+ #
318
+ # t = node['tree']; return unless t
319
+ ##return if t[0] == '_apply'
320
+ # pnode = @execution['nodes'][node['parent']]; return unless pnode
321
+ #
322
+ # pt =
323
+ # pnode['tree'] ||
324
+ # Flor::Node.new(self, pnode, nil).lookup_tree(pnode['nid'])
325
+ # cid =
326
+ # Flor.child_id(node['nid'])
327
+ #
328
+ # if cid == pt[1].size # head "exception"
329
+ # return if pt[0] == t
330
+ # pt[0] = t
331
+ # pnode['tree'] = pt
332
+ # return
333
+ # end
334
+ #
335
+ # pt[1][cid] = t
336
+ # pnode['tree'] = pt
337
+ # end
338
+
304
339
  def leave_tags(message, node)
305
340
 
306
341
  ts = node['tags']; return [] unless ts && ts.any?
@@ -145,27 +145,25 @@ class Flor::Node
145
145
  #
146
146
  # that might be the way...
147
147
 
148
- def lookup(name)
149
-
150
- cat, mod, key = key_split(name)
151
- key, pth = key.split('.', 2)
152
-
153
- val =
154
- if [ cat, mod, key ] == [ 'v', '', 'node' ]
155
- @node
156
- elsif cat == 'v'
157
- lookup_var(@node, mod, key)
158
- elsif cat == 't'
159
- lookup_tag(mod, key)
160
- else
161
- lookup_field(mod, key)
162
- end
148
+ def lookup(name, silence_index_error=false)
149
+
150
+ cat, mod, key_and_path = key_split(name)
151
+ key, pth = key_and_path.split('.', 2)
163
152
 
164
- if pth
165
- Flor.deep_get(val, pth)[1]
153
+ if [ cat, mod, key ] == [ 'v', '', 'node' ]
154
+ lookup_in_node(pth)
155
+ elsif cat == 'v'
156
+ lookup_var(@node, mod, key, pth)
157
+ elsif cat == 't'
158
+ lookup_tag(mod, key)
166
159
  else
167
- val
160
+ lookup_field(mod, key_and_path)
168
161
  end
162
+
163
+ rescue IndexError
164
+
165
+ raise unless silence_index_error
166
+ nil
169
167
  end
170
168
 
171
169
  class Expander < Flor::Dollar
@@ -178,7 +176,8 @@ class Flor::Node
178
176
  return @node.exid if k == 'exid'
179
177
  return Flor.tstamp if k == 'tstamp'
180
178
 
181
- @node.lookup(k)
179
+ r = @node.lookup(k, true)
180
+ r.is_a?(Symbol) ? nil : r
182
181
  end
183
182
  end
184
183
 
@@ -202,10 +201,10 @@ class Flor::Node
202
201
 
203
202
  ref =
204
203
  case v[0]
205
- when '_func' then true
206
- when '_proc' then v[1]['proc'] != o
207
- when '_task' then v[1]['task'] != o
208
- else false
204
+ when '_func' then true
205
+ when '_proc' then v[1]['proc'] != o
206
+ when '_task' then v[1]['task'] != o
207
+ else false
209
208
  end
210
209
 
211
210
  v[1]['oref'] ||= v[1]['ref'] if ref && v[1]['ref']
@@ -226,8 +225,6 @@ class Flor::Node
226
225
  'apply'
227
226
  elsif heat[0] == '_task'
228
227
  'task'
229
- elsif Flor.is_tree_head_tree?(tree)
230
- '_happly'
231
228
  else
232
229
  '_val'
233
230
  end
@@ -317,54 +314,86 @@ class Flor::Node
317
314
  # @execution['nodes'][node['cnid']]
318
315
  #end
319
316
 
320
- def lookup_dvar(mod, key)
317
+ def lookup_in_node(pth)
321
318
 
322
- if mod != 'd' && Flor::Procedure[key]
323
- return [ '_proc', { 'proc' => key }, -1 ]
324
- end
319
+ Flor.deep_get(@node, pth)
320
+ end
325
321
 
326
- l = @executor.unit.loader
327
- vdomain = @node['vdomain']
328
- #
329
- if l && vdomain != false
330
- v = l.variables(vdomain || domain).fetch(key) { :no }
331
- return v unless v == :no
332
- end
322
+ class PseudoVarContainer < Hash
323
+ #
324
+ # inherit from Hash so that deep.rb is quietly mislead
325
+ #
326
+ def initialize(type); @type = type; end
327
+ #def has_key?(key); true; end
328
+ def [](key); [ "_#{@type}", { @type => key }, -1 ]; end
329
+ end
330
+ #
331
+ PROC_VAR_CONTAINER = PseudoVarContainer.new('proc')
332
+ TASKER_VAR_CONTAINER = PseudoVarContainer.new('task')
333
333
 
334
- if mod != 'd' && @executor.unit.has_tasker?(@executor.exid, key)
335
- return [ '_task', { 'task' => key }, -1 ]
336
- end
334
+ def lookup_var(node, mod, key, pth)
337
335
 
338
- nil
336
+ c = lookup_var_container(node, mod, key)
337
+
338
+ kp = [ key, pth ].reject { |x| x == nil || x.size < 1 }.join('.')
339
+
340
+ v = Flor.deep_get(c, kp)
341
+ #p [ mod, key, pth, '->', v ]
342
+
343
+ return v unless v.is_a?(Symbol)
344
+
345
+ vs = v.to_s.split('.')
346
+ tail = vs.pop
347
+ vs = vs.join('.')
348
+
349
+ fail IndexError.new("variable #{tail.inspect} not found") if vs.empty?
350
+ fail IndexError.new("no key #{tail.inspect} in variable #{vs.inspect}")
339
351
  end
340
352
 
341
- def lookup_var(node, mod, key)
353
+ def lookup_var_container(node, mod, key)
342
354
 
343
- return lookup_dvar(mod, key) if node == nil || mod == 'd'
355
+ return lookup_dvar_container(mod, key) if node == nil || mod == 'd'
344
356
 
345
357
  pnode = parent_node(node)
346
- #cnode = closure_node(node)
358
+ vars = node['vars']
347
359
 
348
360
  if mod == 'g'
349
- vars = node['vars']
350
- return lookup_var(pnode, mod, key) if pnode
351
- return vars[key] if vars
352
- #return lookup_var(cnode, mod, key) if cnode
361
+ return lookup_var_container(pnode, mod, key) if pnode
362
+ return vars if vars
353
363
  fail "node #{node['nid']} has no vars and no parent"
354
364
  end
355
365
 
356
- vars = node['vars']
357
-
358
- return vars[key] if vars && vars.has_key?(key)
366
+ return vars if vars && vars.has_key?(key)
359
367
 
360
368
  if cnid = node['cnid']
361
369
  cvars = (@execution['nodes'][cnid] || {})['vars']
362
- return cvars[key] if cvars && cvars.has_key?(key)
370
+ return cvars if cvars && cvars.has_key?(key)
363
371
  end
364
372
  #
365
373
  # look into closure, just one level deep...
366
374
 
367
- lookup_var(pnode, mod, key)
375
+ lookup_var_container(pnode, mod, key)
376
+ end
377
+
378
+ def lookup_dvar_container(mod, key)
379
+
380
+ if mod != 'd' && Flor::Procedure[key]
381
+ return PROC_VAR_CONTAINER
382
+ end
383
+
384
+ l = @executor.unit.loader
385
+ vdomain = @node['vdomain']
386
+ #
387
+ if l && vdomain != false
388
+ vars = l.variables(vdomain || domain)
389
+ return vars if vars.has_key?(key)
390
+ end
391
+
392
+ if mod != 'd' && @executor.unit.has_tasker?(@executor.exid, key)
393
+ return TASKER_VAR_CONTAINER
394
+ end
395
+
396
+ {}
368
397
  end
369
398
 
370
399
  def lookup_var_name(node, val)
@@ -389,9 +418,10 @@ class Flor::Node
389
418
  nids.empty? ? [ '_nul', nil, -1 ] : nids
390
419
  end
391
420
 
392
- def lookup_field(mod, key)
421
+ def lookup_field(mod, key_and_path)
393
422
 
394
- Flor.deep_get(payload.current, key)[1]
423
+ r = Flor.deep_get(payload.current, key_and_path)
424
+ r.is_a?(Symbol) ? nil : r
395
425
  end
396
426
 
397
427
  def key_split(key) # => category, mode, key
@@ -17,12 +17,15 @@ class Flor::Procedure < Flor::Node
17
17
 
18
18
  names = names.flatten
19
19
  @names = names if names.any?
20
+ @core = !! caller.find { |l| l.match(/flor\/pcore/) } if names.any?
20
21
 
21
22
  @names
22
23
  end
23
24
 
24
25
  alias :name :names
25
26
 
27
+ def core?; @core; end
28
+
26
29
  def make(executor, node, message)
27
30
 
28
31
  heap = node['heat'] ? node['heap'] : nil
@@ -234,9 +237,9 @@ class Flor::Procedure < Flor::Node
234
237
  unatt_unkeyed_children(true)
235
238
  end
236
239
 
237
- def stringify_first_child
240
+ def stringify_child(non_att_index)
238
241
 
239
- c = non_att_children.first
242
+ c = non_att_children[non_att_index]
240
243
  return unless c
241
244
  return unless c[1] == [] && c[0].is_a?(String)
242
245
 
@@ -247,6 +250,11 @@ class Flor::Procedure < Flor::Node
247
250
  @node['tree'] = [ tree[0], cn, tree[2] ]
248
251
  end
249
252
 
253
+ def stringify_first_child
254
+
255
+ stringify_child(0)
256
+ end
257
+
250
258
  def do_execute
251
259
 
252
260
  pre_execute
@@ -321,31 +329,37 @@ class Flor::Procedure < Flor::Node
321
329
  []
322
330
  end
323
331
 
324
- def receive
332
+ def determine_fcid_and_ncid
325
333
 
326
334
  @fcid = point == 'receive' ? Flor.child_id(from) : nil
327
335
  @ncid = (@fcid || -1) + 1
336
+ end
328
337
 
329
- return receive_first if @fcid == nil
338
+ def from_att?
339
+
340
+ @fcid && (c = children[@fcid]) && c[0] == '_att'
341
+ end
330
342
 
331
- child = children[@fcid]
343
+ def receive
332
344
 
333
- return receive_att if child && child[0] == '_att'
345
+ determine_fcid_and_ncid
334
346
 
347
+ return receive_first if @fcid == nil
348
+ return receive_att if from_att?
335
349
  receive_non_att
336
350
  end
337
351
 
338
352
  def receive_first
339
353
 
340
- return receive_last_att if children[0] && children[0][0] != '_att'
354
+ return receive_last_att if (c = children[0]) && c[0] != '_att'
341
355
  execute_child(@ncid)
342
356
  end
343
357
 
344
358
  def receive_att
345
359
 
346
- nctree = children[@ncid]
360
+ nt = children[@ncid]
347
361
 
348
- return receive_last_att if nctree == nil || nctree[0] != '_att'
362
+ return receive_last_att if nt == nil || nt[0] != '_att'
349
363
  execute_child(@ncid)
350
364
  end
351
365
 
@@ -477,9 +491,9 @@ class Flor::Procedure < Flor::Node
477
491
 
478
492
  if node
479
493
 
480
- b, v = Flor.deep_set(node['vars'], k, v)
494
+ v = Flor.deep_set(node['vars'], k, v)
481
495
 
482
- return v if b
496
+ return v unless v.is_a?(Symbol)
483
497
  end
484
498
 
485
499
  fail IndexError.new("couldn't set var #{mode}v.#{k}")
@@ -487,9 +501,9 @@ class Flor::Procedure < Flor::Node
487
501
 
488
502
  def set_field(k, v)
489
503
 
490
- success, value = Flor.deep_set(payload.copy, k, v)
504
+ value = Flor.deep_set(payload.copy, k, v)
491
505
 
492
- fail IndexError.new("couldn't set field #{k}") unless success
506
+ fail IndexError.new("couldn't set field #{k}") if value.is_a?(Symbol)
493
507
 
494
508
  value
495
509
  end
@@ -501,10 +515,10 @@ class Flor::Procedure < Flor::Node
501
515
  cat, mod, key = key_split(k)
502
516
 
503
517
  case cat[0, 1]
504
- when 'f' then set_field(key, v)
505
- when 'v' then set_var(mod, key, v)
506
- #when 'w' then set_war(key, v)
507
- else fail IndexError.new("don't know how to set #{k.inspect}")
518
+ when 'f' then set_field(key, v)
519
+ when 'v' then set_var(mod, key, v)
520
+ #when 'w' then set_war(key, v)
521
+ else fail IndexError.new("don't know how to set #{k.inspect}")
508
522
  end
509
523
  end
510
524
 
@@ -516,10 +530,12 @@ class Flor::Procedure < Flor::Node
516
530
 
517
531
  cni = fun[1]['cnid'] # closure nid
518
532
 
519
- t = lookup_tree(fni)
533
+ t = fun[1]['tree']
534
+ t = t || lookup_tree(fni) # TODO when fun[1]['tree'] is settled, drop me
520
535
  fail ArgumentError.new("couldn't find function at #{fni}") unless t
521
536
 
522
- t = t[0] if fun[1]['head']
537
+ t = t[0] if t[0].is_a?(Array)
538
+ t = t[1][0] if t[0] == '_att'
523
539
 
524
540
  sig = t[1].select { |c| c[0] == '_att' }
525
541
  sig = sig.drop(1) if t[0] == 'define'
@@ -629,6 +645,7 @@ class Flor::Macro < Flor::Procedure
629
645
  def rewrite
630
646
 
631
647
  t = rewrite_tree
648
+ #Flor.print_tree(t, nid)
632
649
 
633
650
  m = @message.dup
634
651
  m['tree'] = t