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
@@ -1,5 +1,20 @@
1
1
 
2
2
  class Flor::Pro::Arr < Flor::Procedure
3
+ #
4
+ # "_arr" is the procedure behind arrays.
5
+ #
6
+ # Writing
7
+ # ```
8
+ # [ 1 2 3 ]
9
+ # ```
10
+ # is in fact read as
11
+ # ```
12
+ # _arr
13
+ # 1
14
+ # 2
15
+ # 3
16
+ # ```
17
+ # by flor.
3
18
 
4
19
  name '_arr'
5
20
 
@@ -6,11 +6,12 @@ class Flor::Pro::Atom < Flor::Procedure
6
6
  def execute
7
7
 
8
8
  payload['ret'] =
9
- case tree[0]
10
- when '_dqs' then expand(tree[1])
11
- when '_rxs' then [ tree[0], expand(tree[1]), *tree[2..-1] ]
12
- when '_func' then tree
13
- else tree[1]
9
+ case @node['heat0']
10
+ when '_nul' then nil
11
+ when '_dqs' then expand(tree[1])
12
+ when '_rxs' then [ tree[0], expand(tree[1]), *tree[2..-1] ]
13
+ when '_func' then tree
14
+ else tree[1]
14
15
  end
15
16
 
16
17
  wrap_reply
@@ -121,12 +121,17 @@ class Flor::Pro::Att < Flor::Procedure
121
121
  wrap_reply
122
122
  end
123
123
 
124
- def receive_tag
124
+ def parent_is_trap?
125
+
126
+ pt = parent_node_tree; return false unless pt
127
+ pt0 = pt[0]; return false unless pt0.is_a?(String)
128
+ pro = Flor::Procedure[pt0]; return false unless pro
129
+ pro.names.include?('trap')
130
+ end
125
131
 
126
- pt = parent_node_tree
132
+ def receive_tag
127
133
 
128
- return receive_att('tags') \
129
- if pt && pt[0].is_a?(String) && Flor::Procedure[pt[0]].names[0] == 'trap'
134
+ return receive_att('tags') if parent_is_trap?
130
135
 
131
136
  ret = payload['ret']
132
137
  ret = unref(ret, :att)
@@ -1,5 +1,21 @@
1
1
 
2
2
  class Flor::Pro::Obj < Flor::Procedure
3
+ #
4
+ # "_obj" is the procedure behind objects (maps).
5
+ #
6
+ # Writing
7
+ # ```
8
+ # { a: 1, b: 2 }
9
+ # ```
10
+ # is in fact read as
11
+ # ```
12
+ # _obj
13
+ # 'a'
14
+ # 1
15
+ # 'b'
16
+ # 2
17
+ # ```
18
+ # by flor.
3
19
 
4
20
  name '_obj'
5
21
 
@@ -9,53 +25,31 @@ class Flor::Pro::Obj < Flor::Procedure
9
25
  @node['atts'] = []
10
26
  end
11
27
 
12
- def receive_last_att
28
+ def execute_child(index=0, sub=nil, h=nil)
13
29
 
14
- return super unless att('quote') == 'keys'
15
-
16
- t0 = tree
17
- t1 = Flor.dup(t0)
18
-
19
- (@ncid..t1[1].length - 1).step(2) do |i|
20
-
21
- c = t1[1][i]
22
-
23
- t1[1][i] = [ '_sqs', c[0], *c[2..-1] ] if c[0].is_a?(String) && c[1] == []
24
- end
25
-
26
- @node['tree'] = t1 if t1 != t0
27
-
28
- super
29
- end
30
+ return wrap_reply('ret' => {}) if children == 0
30
31
 
31
- def receive_first
32
+ return super if @node['rets'].size.odd?
32
33
 
33
- return wrap_reply('ret' => {}) if children == 0
34
+ ct = children[index]
35
+ q = (att('quote') == 'keys')
34
36
 
35
- cn = children
36
- .inject([]) { |a, e| a << (a.size.even? ? stringify(e) : e); a }
37
+ return super unless ct[1] == [] && (deref(ct[0]) == nil || q)
37
38
 
38
- @node['tree'] = [ tree[0], cn, tree[2] ] if children != cn
39
+ t = tree
40
+ t[1][index] = [ '_sqs', ct[0], *ct[2..-1] ]
41
+ @node['tree'] = t
39
42
 
40
43
  super
41
44
  end
42
45
 
43
46
  def receive_last
44
47
 
45
- payload['ret'] =
46
- @node['rets']
47
- .each_slice(2)
48
- .inject({}) { |h, (k, v)| h[k.to_s] = v; h }
48
+ payload['ret'] = @node['rets']
49
+ .each_slice(2)
50
+ .inject({}) { |h, (k, v)| h[k.to_s] = v; h }
49
51
 
50
52
  wrap_reply
51
53
  end
52
-
53
- protected
54
-
55
- def stringify(t)
56
-
57
- return t unless t[1] == [] && t[0].is_a?(String)
58
- [ '_sqs', deref(t[0]) || t[0], t[2] ]
59
- end
60
54
  end
61
55
 
@@ -0,0 +1,77 @@
1
+
2
+ class Flor::Pro::PatContainer < Flor::Procedure
3
+
4
+ def pre_execute
5
+
6
+ @node['binding'] = {}
7
+ end
8
+
9
+ def execute
10
+
11
+ if tree[1] == 0 || tree[1] == []
12
+ payload['_pat_binding'] = val == [] ? {} : nil
13
+ payload.delete('_pat_val')
14
+ return wrap_reply
15
+ end
16
+
17
+ super
18
+ end
19
+
20
+ def execute_child(index=0, sub=nil, h=nil)
21
+
22
+ ct = child_type(index)
23
+
24
+ if ct == :pattern || ct.is_a?(Array)
25
+ @node['_sub_pat_val'] = sv = sub_val(index)
26
+ payload['_pat_val'] = sv[1]
27
+ else
28
+ @node.delete('_sub_pat_val')
29
+ payload.delete('_pat_val')
30
+ end
31
+
32
+ return wrap_reply(
33
+ 'nid' => nid, 'from' => Flor.child_nid(nid, index, sub)
34
+ ) if ct.is_a?(String) || ct.is_a?(Array)
35
+
36
+ super(index, sub, h)
37
+ end
38
+
39
+ protected
40
+
41
+ def val
42
+
43
+ node_payload['_pat_val'] || node_payload_ret
44
+ end
45
+
46
+ # A default implementation
47
+ #
48
+ def sub_val(child_index)
49
+
50
+ [ 1, val ]
51
+ end
52
+
53
+ def child_type(cid_or_tree)
54
+
55
+ ct = cid_or_tree.is_a?(Array) ? cid_or_tree : tree[1][cid_or_tree]
56
+ ct0 = ct[0]
57
+
58
+ return :att if ct0 == '_att'
59
+ return :pattern if /\A_pat_(arr|obj|or|guard)\z/ === ct0
60
+ return '_' if ct0 == '_'
61
+ return ct0 if /\A[a-z][a-z0-9]*\z/ === ct0 && ct[1] == []
62
+
63
+ m = ct0.match(Flor::SPLAT_REGEX)
64
+ return [ m[1], m[2] == '_' ? nil : m[2].to_i ] if m
65
+
66
+ nil # nothing special
67
+ end
68
+
69
+ def wrap_no_match_reply
70
+
71
+ payload['_pat_binding'] = nil
72
+ payload.delete('_pat_val')
73
+
74
+ wrap_reply
75
+ end
76
+ end
77
+
@@ -0,0 +1,131 @@
1
+
2
+ require 'flor/pcore/_pat_'
3
+
4
+
5
+ class Flor::Pro::PatArr < Flor::Pro::PatContainer
6
+
7
+ name '_pat_arr'
8
+
9
+ def pre_execute
10
+
11
+ @node['index'] = 0
12
+
13
+ super
14
+ end
15
+
16
+ def receive_first
17
+
18
+ return wrap_no_match_reply unless val.is_a?(Array)
19
+
20
+ super
21
+ end
22
+
23
+ def receive_non_att
24
+
25
+ ct = child_type(@fcid)
26
+ #p [ :rna, :fcid, @fcid, :index, @node['index'], :ct, ct ]
27
+
28
+ offset = 1
29
+
30
+ if ct == :pattern
31
+
32
+ if b = payload.delete('_pat_binding')
33
+ offset, _ = @node['_sub_pat_val']
34
+ @node['binding'].merge!(b)
35
+ else
36
+ return wrap_no_match_reply
37
+ end
38
+
39
+ elsif ct.is_a?(String)
40
+
41
+ @node['binding'][ct] = val[@node['index']] if ct != '_'
42
+
43
+ elsif ct.is_a?(Array)
44
+
45
+ offset, v = @node['_sub_pat_val']
46
+ @node['binding'][ct[0]] = v if ct[0].length > 0
47
+
48
+ elsif val[@node['index']] != payload['ret']
49
+
50
+ return wrap_no_match_reply
51
+ end
52
+
53
+ @node['index'] = @node['index'] + offset
54
+
55
+ return wrap_no_match_reply if @node['index'] > val.size
56
+
57
+ super
58
+ end
59
+
60
+ def receive_last
61
+
62
+ return wrap_no_match_reply if @node['index'] < val.size
63
+
64
+ payload['_pat_binding'] = @node['binding']
65
+ payload.delete('_pat_val')
66
+
67
+ super
68
+ end
69
+
70
+ protected
71
+
72
+ def sub_val(child_index)
73
+
74
+ ct = child_type(child_index)
75
+
76
+ q =
77
+ if ct.is_a?(Array)
78
+ ct
79
+ elsif ct == :pattern
80
+ count_pat(child_index, false)
81
+ else
82
+ nil
83
+ end
84
+
85
+ if q && q.is_a?(Array)
86
+ count = val[@node['index']..-1].size - remaining_index_count
87
+ count = q[1] if q[1] && count > q[1]
88
+ sv = val[@node['index'], count]
89
+ [ sv.size, sv ]
90
+ else
91
+ [ 1, val[@node['index']] ]
92
+ end
93
+ end
94
+
95
+ def remaining_index_count(ncid=@ncid)
96
+
97
+ (ncid + 1..children.size - 1).to_a
98
+ .inject(0) { |count, cid|
99
+ count +
100
+ case (ct = child_type(cid))
101
+ when :att then 0
102
+ when :pattern then count_pat(cid)
103
+ when Array then count_arr(ct)
104
+ else 1
105
+ end }
106
+ end
107
+
108
+ def count_arr(a)
109
+
110
+ a[1] || 1 # really?
111
+ end
112
+
113
+ def count_pat(cid, squash=true)
114
+
115
+ ct = children[cid]
116
+ return 1 if ct[0] != '_pat_guard'
117
+
118
+ ct = ct[1][0]
119
+ return 1 if ct[1] != []
120
+
121
+ m = ct[0].match(Flor::SPLAT_REGEX)
122
+ return 1 if m == nil
123
+
124
+ if squash
125
+ m[2] == '_' ? 1 : m[2].to_i
126
+ else
127
+ [ m[1], m[2] == '_' ? nil : m[2].to_i ]
128
+ end
129
+ end
130
+ end
131
+
@@ -0,0 +1,70 @@
1
+
2
+ require 'flor/pcore/_pat_'
3
+
4
+
5
+ class Flor::Pro::PatGuard < Flor::Pro::PatContainer
6
+
7
+ name '_pat_guard'
8
+
9
+ # ```
10
+ # _pat_guard name
11
+ # _pat_guard name pattern
12
+ # _pat_guard name conditional
13
+ # _pat_guard name pattern conditional
14
+ # _pat_guard name conditional pattern
15
+ # ```
16
+
17
+ def pre_execute
18
+
19
+ unatt_unkeyed_children
20
+ stringify_first_child
21
+
22
+ @node['binding'] = {}
23
+ end
24
+
25
+ def receive_non_att
26
+
27
+ ct = child_type(@fcid)
28
+
29
+ if ct == nil && @node['key'] == nil && payload['ret'].is_a?(String)
30
+
31
+ k = payload['ret']
32
+ m = k.match(Flor::SPLAT_REGEX)
33
+ k = m ? k[0] : k
34
+
35
+ @node['key'] = k
36
+ @node['binding'].merge!(k => val) if k != '_'
37
+
38
+ elsif ct == nil && payload['ret'] == false
39
+
40
+ return wrap_no_match_reply
41
+
42
+ elsif ct == :pattern
43
+
44
+ b = payload['_pat_binding']
45
+ return wrap_no_match_reply unless b
46
+
47
+ @node['binding'].merge!(b)
48
+ end
49
+
50
+ super
51
+ end
52
+
53
+ def receive_last
54
+
55
+ payload['_pat_binding'] = @node['binding']
56
+
57
+ super
58
+ end
59
+
60
+ def execute_child(index=0, sub=nil, h=nil)
61
+
62
+ if (key = @node['key']) && child_type(index) == nil
63
+ h ||= {}
64
+ (h['vars'] ||= {}).merge!(@node['binding'])
65
+ end
66
+
67
+ super(index, sub, h)
68
+ end
69
+ end
70
+
@@ -0,0 +1,143 @@
1
+
2
+ require 'flor/pcore/_pat_'
3
+
4
+
5
+ class Flor::Pro::PatObj < Flor::Pro::PatContainer
6
+
7
+ name '_pat_obj'
8
+
9
+ def pre_execute
10
+
11
+ @node['atts'] = []
12
+
13
+ t = tree
14
+
15
+ if (
16
+ i = t[1].index { |ct|
17
+ ct[0] == '_att' &&
18
+ ct[1].size == 1 &&
19
+ ct[1][0][0, 2] == [ 'only', [] ] }
20
+ ) then
21
+ t[1][i] =
22
+ [ '_att', [
23
+ [ '_sqs', 'only', -1 ],
24
+ [ '_boo', true, -1 ],
25
+ ], *t[1][i][2..-1] ]
26
+ @node['tree'] = [ t[0], t[1], *t[1][2..-1] ]
27
+ end
28
+
29
+ super
30
+ end
31
+
32
+ def receive_first
33
+
34
+ return wrap_no_match_reply unless val.is_a?(Hash)
35
+
36
+ super
37
+ end
38
+
39
+ def receive_last_att
40
+
41
+ rewrite_keys
42
+
43
+ @node['key'] = nil
44
+ @node['keys'] = [] if att('only')
45
+
46
+ super
47
+ end
48
+
49
+ def receive_non_att
50
+
51
+ key = @node['key']
52
+ ret = payload['ret']
53
+
54
+ unless key
55
+ ret = ret.to_s
56
+ return wrap_no_match_reply unless Flor.deep_has_key?(val, ret)
57
+ @node['key'] = ret
58
+ @node['keys'] << ret if @node['keys']
59
+ return super
60
+ end
61
+
62
+ ct = child_type(@fcid)
63
+
64
+ if ct == :pattern
65
+
66
+ if b = payload.delete('_pat_binding')
67
+ @node['binding'].merge!(b)
68
+ else
69
+ return wrap_no_match_reply
70
+ end
71
+
72
+ elsif ct.is_a?(String)
73
+
74
+ @node['binding'][ct] = val[@node['key']] if ct != '_'
75
+
76
+ elsif ct.is_a?(Array)
77
+
78
+ @node['binding'][ct[0]] = val[@node['key']] if ct[0].length > 0
79
+
80
+ elsif Flor.deep_get(val, key) != ret
81
+
82
+ return wrap_no_match_reply
83
+ end
84
+
85
+ @node['key'] = nil
86
+
87
+ super
88
+ end
89
+
90
+ def receive_last
91
+
92
+ ks = @node['keys']
93
+ return wrap_no_match_reply if ks && val.keys.sort != ks.sort
94
+
95
+ payload['_pat_binding'] = @node['binding']
96
+ payload.delete('_pat_val')
97
+
98
+ super
99
+ end
100
+
101
+ protected
102
+
103
+ def rewrite_keys
104
+
105
+ q = (att('quote') == 'keys')
106
+
107
+ key = true
108
+
109
+ cn = children
110
+ .collect { |ct|
111
+ next ct if ct[0] == '_att'
112
+ key = ! key
113
+ next ct if key
114
+ q ? quote_key(ct) : lookup_and_quote_key(ct) }
115
+
116
+ t = tree
117
+
118
+ @node['tree'] = [ t[0], cn, *t[2..-1] ] if cn != t[1]
119
+ end
120
+
121
+ def quote_key(t)
122
+
123
+ if t[1] == []
124
+ [ '_sqs', t[0], *t[2..-1] ]
125
+ elsif t[1].is_a?(Array)
126
+ t
127
+ else
128
+ [ '_sqs', t[1].to_s, *t[2..-1] ]
129
+ end
130
+ end
131
+
132
+ def lookup_and_quote_key(t)
133
+
134
+ return t unless t[1] == []
135
+ [ '_sqs', lookup(t[0], true) || t[0], t[2] ]
136
+ end
137
+
138
+ def sub_val(child_index)
139
+
140
+ [ 1, val[@node['key']] ]
141
+ end
142
+ end
143
+