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
@@ -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