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