flor 0.13.0 → 0.14.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 (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
@@ -182,7 +182,10 @@ module Flor
182
182
 
183
183
  vs = Hash.new { |h, k| k }
184
184
  class << vs
185
- def has_key?(k); ! Flor::Procedure[k]; end
185
+ def has_key?(k)
186
+ prc = Flor::Procedure[k]
187
+ ( ! prc) || ( ! prc.core?) # ignore non-core procedures
188
+ end
186
189
  end
187
190
 
188
191
  vs['root'] = determine_root(path)
@@ -32,97 +32,89 @@ module Flor
32
32
  end }
33
33
  end
34
34
 
35
- def self.deep_get(o, k) # --> success(boolean), value
35
+ # Returns a symbol in case of failure.
36
+ #
37
+ def self.deep_get(o, k)
36
38
 
37
- return [ true, o ] unless k
39
+ return o unless k
38
40
 
39
- val = o
41
+ split_deep_path(k).inject([ o, [] ]) do |(val, seen), kk|
40
42
 
41
- split_deep_path(k).each do |kk|
43
+ seen << kk
42
44
 
43
45
  case val
44
46
  when Array
45
47
  i = to_array_index(kk)
46
- return [ false, nil ] unless i
47
- val = val[i]
48
+ return seen.join('.').to_sym unless i
49
+ [ val[i], seen ]
48
50
  when Hash
49
- val = val[kk]
51
+ [ val[kk], seen ]
50
52
  else
51
- return [ false, nil ]
53
+ return seen[0..-2].join('.').to_sym
52
54
  end
53
- end
54
55
 
55
- [ true, val ]
56
+ end.first
56
57
  end
57
58
 
58
- def self.deep_set(o, k, v) # --> [ success(boolean), value ]
59
+ def self.deep_set(o, k, v)
59
60
 
60
61
  ks = split_deep_path(k)
61
62
  key = ks.pop
62
-
63
- b, col = deep_get(o, ks)
64
-
65
- return [ false, v ] unless b
63
+ col = deep_get(o, ks)
66
64
 
67
65
  case col
66
+ when Symbol
67
+ col
68
68
  when Array
69
69
  i = to_array_index(key)
70
- return [ false, v ] unless i
70
+ return ks.join('.').to_sym unless i
71
71
  col[i] = v
72
72
  when Hash
73
73
  col[key] = v
74
74
  else
75
- return [ false, v ]
75
+ ks.join('.').to_sym
76
76
  end
77
-
78
- [ true, v ]
79
77
  end
80
78
 
81
- def self.deep_insert(o, k, v) # --> [ success(boolean), value ]
79
+ def self.deep_insert(o, k, v)
82
80
 
83
81
  ks = split_deep_path(k)
84
82
  key = ks.pop
85
-
86
- b, col = deep_get(o, ks)
87
-
88
- return [ false, nil ] unless b
83
+ col = deep_get(o, ks)
89
84
 
90
85
  case col
86
+ when Symbol
87
+ col
91
88
  when Array
92
89
  i = to_array_index(key)
93
- return [ false, v ] unless i
90
+ return ks.join('.').to_sym unless i
94
91
  col.insert(i, v)
92
+ v
95
93
  when Hash
96
94
  col[key] = v
97
95
  else
98
- return [ false, v ]
96
+ ks.join('.').to_sym
99
97
  end
100
-
101
- [ true, v ]
102
98
  end
103
99
 
104
- def self.deep_unset(o, k) # --> [ success(boolean), value ]
100
+ def self.deep_unset(o, k)
105
101
 
106
102
  ks = split_deep_path(k)
107
103
  key = ks.pop
104
+ col = deep_get(o, ks)
108
105
 
109
- b, col = deep_get(o, ks)
110
-
111
- return [ false, nil ] unless b
112
-
113
- v =
114
- case col
115
- when Array
116
- i = to_array_index(key)
117
- return [ false, nil ] unless i
118
- col.delete_at(i)
119
- when Hash
120
- col.delete(key)
121
- else
122
- return [ false, nil ]
123
- end
124
-
125
- [ true, v ]
106
+ case col
107
+ when Symbol
108
+ col
109
+ when Array
110
+ i = to_array_index(key)
111
+ return ks.join('.').to_sym unless i
112
+ col.delete_at(i)
113
+ when Hash
114
+ col.delete(key)
115
+ else
116
+ return ks.join('.').to_sym
117
+ end
126
118
  end
127
119
 
128
120
  def self.deep_has_key?(o, k)
@@ -137,14 +129,14 @@ module Flor
137
129
  case val
138
130
  when Array
139
131
  i = to_array_index(kk)
140
- return false unless i
141
- return (i < 0 ? -i < val.length : i < val.length) if ks.empty?
132
+ break false unless i
133
+ break (i < 0 ? -i < val.length : i < val.length) if ks.empty?
142
134
  val = val[i]
143
135
  when Hash
144
- return val.has_key?(kk) if ks.empty?
145
- val = val[kk]
136
+ break val.has_key?(kk.to_s) if ks.empty? # nota bene: #to_s
137
+ val = val[kk.to_s]
146
138
  else
147
- return false
139
+ break false
148
140
  end
149
141
  end
150
142
  end
@@ -61,7 +61,7 @@ module Flor
61
61
  def rewrite_span(t)
62
62
  t.children.collect { |c| rewrite(c) }
63
63
  end
64
- end
64
+ end # module Parser
65
65
 
66
66
  module PipeParser include Raabro
67
67
 
@@ -72,7 +72,7 @@ module Flor
72
72
  def rewrite_elt(t); t.string; end
73
73
  def rewrite_pipe(t); t.string == '|' ? :pipe : :dpipe; end
74
74
  def rewrite_elts(t); t.children.collect { |e| rewrite(e) }; end
75
- end
75
+ end # module PipeParser
76
76
 
77
77
  #def lookup(s)
78
78
  # # ...
@@ -196,7 +196,6 @@ module Flor
196
196
 
197
197
  result =
198
198
  if mode == :lookup
199
- #k[0, 1] == "'" ? k[1..-1] : do_lookup(k)
200
199
  k[0, 1] == "'" ? k[1..-1] : lookup(k)
201
200
  else # :call
202
201
  call(k, result)
@@ -264,16 +264,26 @@ module Flor
264
264
  t[2].is_a?(Integer)
265
265
  end
266
266
 
267
+ def self.is_string_tree?(t, s=nil)
268
+
269
+ t.is_a?(Array) &&
270
+ t[2].is_a?(Integer) &&
271
+ %w[ _sqs _dqs ].include?(t[0]) &&
272
+ (s ? (t[1] == s) : t[1].is_a?(String))
273
+ end
274
+
267
275
  def self.is_att_tree?(t)
268
276
 
269
277
  t.is_a?(Array) &&
278
+ t[2].is_a?(Integer) &&
270
279
  t[0] == '_att' &&
271
280
  t[1].is_a?(Array)
272
281
  end
273
282
 
274
283
  def self.is_array_of_trees?(o)
275
284
 
276
- o.is_a?(Array) && o.all? { |e| Flor.is_tree?(e) }
285
+ o.is_a?(Array) &&
286
+ o.all? { |e| Flor.is_tree?(e) }
277
287
  end
278
288
 
279
289
  # # Array, object or atom tree
@@ -311,14 +321,6 @@ module Flor
311
321
  o[1]['task'].is_a?(String)
312
322
  end
313
323
 
314
- def self.is_tree_head_tree?(o)
315
-
316
- o.is_a?(Array) &&
317
- Flor.is_tree?(o[0]) &&
318
- Flor.is_array_of_trees?(o[1]) &&
319
- o[2].is_a?(Integer)
320
- end
321
-
322
324
  # Returns [ st, i ], the parent subtree for the final i index of the nid
323
325
  # Used when inserting updated subtrees.
324
326
  #
@@ -343,5 +345,32 @@ module Flor
343
345
  return st if i == nil
344
346
  st[1][i]
345
347
  end
348
+
349
+
350
+ #
351
+ # splat
352
+
353
+ SPLAT_REGEX = /\A(.*)__(_|\d+)\z/.freeze
354
+
355
+ def self.splat(keys, array)
356
+
357
+ ks = keys.dup
358
+ a = array.dup
359
+ h = {}
360
+
361
+ while k = ks.shift
362
+
363
+ if m = SPLAT_REGEX.match(k)
364
+ r, l = m[1, 2]
365
+ l = (l == '_') ? a.length - ks.length : l.to_i
366
+ h[r] = a.take(l) if r.length > 0
367
+ a = a.drop(l)
368
+ else
369
+ h[k] = a.shift
370
+ end
371
+ end
372
+
373
+ h
374
+ end
346
375
  end
347
376
 
@@ -19,7 +19,10 @@ module Flor
19
19
  def pbend(i); str(nil, i, '}'); end
20
20
 
21
21
  def null(i); str(:null, i, 'null'); end
22
- def number(i); rex(:number, i, /-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/); end
22
+
23
+ def number(i)
24
+ rex(:number, i, /[-+]?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)
25
+ end
23
26
 
24
27
  def tru(i); str(nil, i, 'true'); end
25
28
  def fls(i); str(nil, i, 'false'); end
@@ -99,13 +102,15 @@ module Flor
99
102
  # %w[ or or ], %w[ and and ],
100
103
  # %w[ equ == != <> ], %w[ lgt < > <= >= ], %w[ sum + - ], %w[ prd * / % ],
101
104
 
102
- def ssprd(i); rex(:sop, i, /[\*\/%]/); end
105
+ def ssmod(i); str(:sop, i, /%/); end
106
+ def ssprd(i); rex(:sop, i, /[\*\/]/); end
103
107
  def sssum(i); rex(:sop, i, /[+-]/); end
104
108
  def sslgt(i); rex(:sop, i, /(<=?|>=?)/); end
105
109
  def ssequ(i); rex(:sop, i, /(==?|!=|<>)/); end
106
110
  def ssand(i); str(:sop, i, 'and'); end
107
111
  def ssor(i); str(:sop, i, 'or'); end
108
112
 
113
+ def smod(i); seq(nil, i, :ssmod, :eol, '?'); end
109
114
  def sprd(i); seq(nil, i, :ssprd, :eol, '?'); end
110
115
  def ssum(i); seq(nil, i, :sssum, :eol, '?'); end
111
116
  def slgt(i); seq(nil, i, :sslgt, :eol, '?'); end
@@ -113,7 +118,8 @@ module Flor
113
118
  def sand(i); seq(nil, i, :ssand, :eol, '?'); end
114
119
  def sor(i); seq(nil, i, :ssor, :eol, '?'); end
115
120
 
116
- def eprd(i); jseq(:exp, i, :val_ws, :sprd); end
121
+ def emod(i); jseq(:exp, i, :val_ws, :smod); end
122
+ def eprd(i); jseq(:exp, i, :emod, :sprd); end
117
123
  def esum(i); jseq(:exp, i, :eprd, :ssum); end
118
124
  def elgt(i); jseq(:exp, i, :esum, :slgt); end
119
125
  def eequ(i); jseq(:exp, i, :elgt, :sequ); end
@@ -208,37 +214,52 @@ module Flor
208
214
  rewrite(t.c0)
209
215
  end
210
216
 
217
+ def invert(operation, operand)
218
+
219
+ l = operand[2]
220
+
221
+ case operation
222
+ when '+'
223
+ if operand[0] == '_num' && operand[1].is_a?(Numeric)
224
+ [ operand[0], - operand[1], l ]
225
+ else
226
+ [ '-', [ operand ], l ]
227
+ end
228
+ when '*'
229
+ [ '/', [ [ 'num', 1, l ], operand ], l ]
230
+ else
231
+ fail "don't know how to invert #{operation.inspect}" # FIXME
232
+ end
233
+ end
234
+
211
235
  def rewrite_exp(t)
212
236
 
213
237
  return rewrite(t.c0) if t.children.size == 1
214
238
 
215
- cn = [ rewrite(t.c0) ]
216
- op = t.lookup(:sop).string
239
+ cn = t.children.collect { |ct| ct.lookup(nil) }
217
240
 
218
- tcn = t.children[2..-1].dup
241
+ operation = cn.find { |ct| ct.name == :sop }.string
219
242
 
220
- loop do
221
- c = tcn.shift; break unless c
222
- cn << rewrite(c)
223
- o = tcn.shift; break unless o
224
- o = o.lookup(:sop).string
225
- next if o == op
226
- cn = [ [ op, cn, cn.first[2] ] ]
227
- op = o
228
- end
243
+ operator = operation
244
+ operands = []
229
245
 
230
- if op == '-' && cn.all? { |c| c[0] == '_num' }
231
- op = '+'
232
- cn[1..-1].each { |c| c[1] = -c[1] }
246
+ cn.each do |ct|
247
+ if ct.name == :sop
248
+ operator = ct.string
249
+ else
250
+ o = rewrite(ct)
251
+ o = invert(operation, o) if operator != operation
252
+ operands << o
253
+ end
233
254
  end
234
255
 
235
- [ op, cn, cn.first[2] ]
256
+ [ operation, operands, operands.first[2] ]
236
257
  end
237
258
 
238
259
  class Nod
239
260
 
240
261
  attr_accessor :parent, :indent
241
- attr_reader :children
262
+ attr_reader :type, :children
242
263
 
243
264
  def initialize(tree, outdent)
244
265
 
@@ -275,64 +296,65 @@ module Flor
275
296
 
276
297
  def to_a
277
298
 
299
+ return [ @head, @children, @line ] unless @children.is_a?(Array)
278
300
  return @head if @head.is_a?(Array) && @children.empty?
279
301
 
280
302
  cn = @children.collect(&:to_a)
281
303
 
282
- # make sure `[ 1 2 3 ] timeout: '2h'`
283
- # turns into `_arr timeout: '2h'; 1 | 2 | 3`
304
+ as, non_atts = cn.partition { |c| c[0] == '_att' }
305
+ atts, suff = [], nil
284
306
 
285
- if (
286
- @head.is_a?(Array) &&
287
- (@head[0] == '_arr' || @head[0] == '_obj') &&
288
- #Flor.is_array_of_trees?(@head[1]) &&
289
- cn.all? { |c| c[0] == '_att' && c[1].size > 1 }
290
- )
291
- cn = @head[1] + cn
292
- @head = @head[0]
293
- att, non_att = cn.partition { |c| c[0] == '_att' }
294
- cn = att + non_att
295
- end
307
+ as.each do |c|
296
308
 
297
- # detect if/unless suffix
309
+ c1 = c[1]; c10 = c1.size == 1 && c1[0]
310
+ suff = [] if c10 && c10[1] == [] && %w[ if unless ].include?(c10[0])
298
311
 
299
- atts =
300
- cn.inject([]) { |a, c| a << c[1] if c[0] == '_att'; a }
301
- i =
302
- atts.index { |c|
303
- c.size == 1 && %w[ if unless ].include?(c[0][0]) && c[0][1] == []
304
- }
312
+ (suff || atts) << c
313
+ end
305
314
 
306
- return [ @head, cn, @line ] unless i
315
+ atts, non_atts = ta_rework_arr_or_obj(atts, non_atts)
307
316
 
308
- # rewrite if/unless suffix
317
+ core = [ @head, atts + non_atts, @line ]
318
+ core = core[0] if core[0].is_a?(Array) && core[1].empty?
319
+ core = ta_rework_core(core) if core[0].is_a?(Array)
309
320
 
310
- t = [ atts[i][0][0] == 'if' ? 'if' : 'unless', [], @line ]
311
- t[1].concat(atts[i + 1..-1].collect(&:first))
321
+ return core unless suff
312
322
 
313
- cn0i = cn[0, i]; if Flor.is_tree?(@head) && cn0i == []
314
- t[1].push(@head)
315
- else
316
- t[1].push([ @head, cn0i, @line ])
317
- end
323
+ iou = suff.shift[1][0][0]
318
324
 
319
- t
325
+ [ iou, [ suff.first[1].first, core ], @line ]
320
326
  end
321
327
 
322
328
  protected
323
329
 
330
+ def ta_rework_arr_or_obj(atts, non_atts)
331
+
332
+ return [ atts, non_atts ] unless (
333
+ @head.is_a?(Array) &&
334
+ non_atts.empty? &&
335
+ %w[ _arr _obj ].include?(@head[0]))
336
+
337
+ cn = @head[1] + atts + non_atts
338
+ @head = @head[0]
339
+
340
+ cn.partition { |c| c[0] == '_att' }
341
+ end
342
+
343
+ def ta_rework_core(core)
344
+
345
+ l = core[2]
346
+
347
+ [ 'sequence', [
348
+ [ 'set', [
349
+ [ 'head_', [], l ],
350
+ core[0]
351
+ ], l ],
352
+ [ 'head_', core[1], l ]
353
+ ], l ]
354
+ end
355
+
324
356
  def read(tree)
325
357
 
326
- #if it = tree.lookup(:indent)
327
- # #s = it.string
328
- # #semicount = s.count(';')
329
- # #pipe = s.index('|')
330
- # #
331
- # #@indent =
332
- # # if semicount == 1 then :east
333
- # # elsif semicount > 1 || pipe then :south
334
- # # else s.length; end
335
- #end
336
358
  @indent = tree.lookup(:indent).string.length
337
359
 
338
360
  ht = tree.lookup(:head)
@@ -341,8 +363,8 @@ module Flor
341
363
  @head = Flor::Lang.rewrite(ht.c0)
342
364
  @head = @head[0] if @head[0].is_a?(String) && @head[1] == []
343
365
 
344
- atts =
345
- tree.children[2..-1].inject([]) do |as, ct|
366
+ atts = tree.children[2..-1]
367
+ .inject([]) { |as, ct|
346
368
 
347
369
  kt = ct.children.size == 3 ? ct.children[1].lookup(:key) : nil
348
370
  v = Flor::Lang.rewrite(ct.clast)
@@ -350,20 +372,50 @@ module Flor
350
372
  if kt
351
373
  k = Flor::Lang.rewrite(kt.c0)
352
374
  as << [ '_att', [ k, v ], k[2] ]
353
- elsif %w[ - + ].include?(@head) && v[0, 2] != [ '_', [] ]
354
- if v[0] == '+'
355
- as.concat(v[1])
356
- else
357
- as << v
358
- end
359
375
  else
360
376
  as << [ '_att', [ v ], v[2] ]
361
377
  end
362
378
 
363
- as
364
- end
379
+ as }
365
380
 
366
381
  @children.concat(atts)
382
+
383
+ rework_subtraction if @head == '-'
384
+ rework_addition if @head == '+' || @head == '-'
385
+ end
386
+
387
+ def rework_subtraction
388
+
389
+ return unless @children.size == 1
390
+
391
+ c = @children.first
392
+ return unless c[0] == '_att' && c[1].size == 1
393
+
394
+ c = c[1].first
395
+
396
+ if c[0] == '_num'
397
+ @head = '_num'
398
+ @children = - c[1]
399
+ elsif %w[ - + ].include?(c[0])
400
+ @head = c[0]
401
+ @children = c[1]
402
+ @children[0] = Flor::Lang.invert('+', @children[0])
403
+ end
404
+ end
405
+
406
+ def rework_addition
407
+
408
+ katts, atts, cn = @children
409
+ .inject([ [], [], [] ]) { |cn, ct|
410
+ if ct[0] == '_att'
411
+ cn[ct[1].size == 2 ? 0 : 1] << ct
412
+ else
413
+ cn[2] << ct
414
+ end
415
+ cn }
416
+
417
+ @children =
418
+ katts + atts.collect { |ct| ct[1].first } + cn
367
419
  end
368
420
  end
369
421
 
@@ -371,10 +423,9 @@ module Flor
371
423
 
372
424
  prev = root = Nod.new(nil, nil)
373
425
 
374
- #t.gather(:node).each do |nt|
375
426
  t.gather(:line).each do |lt|
376
427
  nt = lt.lookup(:node); next unless nt
377
- ot = lt.lookup(:outdent).string
428
+ ot = lt.children.last.string
378
429
  n = Nod.new(nt, ot)
379
430
  prev.append(n)
380
431
  prev = n