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.
- data/CHANGELOG.md +8 -0
- data/lib/flor.rb +1 -1
- data/lib/flor/core.rb +7 -0
- data/lib/flor/core/executor.rb +43 -8
- data/lib/flor/core/node.rb +84 -54
- data/lib/flor/core/procedure.rb +36 -19
- data/lib/flor/core/texecutor.rb +4 -1
- data/lib/flor/deep.rb +43 -51
- data/lib/flor/dollar.rb +2 -3
- data/lib/flor/flor.rb +38 -9
- data/lib/flor/parser.rb +123 -72
- data/lib/flor/pcore/_arr.rb +15 -0
- data/lib/flor/pcore/_atom.rb +6 -5
- data/lib/flor/pcore/_att.rb +9 -4
- data/lib/flor/pcore/_obj.rb +28 -34
- data/lib/flor/pcore/_pat_.rb +77 -0
- data/lib/flor/pcore/_pat_arr.rb +131 -0
- data/lib/flor/pcore/_pat_guard.rb +70 -0
- data/lib/flor/pcore/_pat_obj.rb +143 -0
- data/lib/flor/pcore/_pat_or.rb +46 -0
- data/lib/flor/pcore/_val.rb +20 -0
- data/lib/flor/pcore/arith.rb +7 -1
- data/lib/flor/pcore/case.rb +46 -69
- data/lib/flor/pcore/cursor.rb +24 -24
- data/lib/flor/pcore/define.rb +5 -1
- data/lib/flor/pcore/do_return.rb +32 -0
- data/lib/flor/pcore/length.rb +18 -0
- data/lib/flor/pcore/logo.rb +47 -0
- data/lib/flor/pcore/map.rb +12 -10
- data/lib/flor/pcore/match.rb +276 -0
- data/lib/flor/pcore/not.rb +13 -0
- data/lib/flor/pcore/push.rb +52 -13
- data/lib/flor/pcore/range.rb +69 -0
- data/lib/flor/pcore/set.rb +82 -24
- data/lib/flor/unit/hook.rb +28 -0
- data/lib/flor/unit/hooker.rb +5 -0
- data/lib/flor/unit/loader.rb +4 -1
- data/lib/flor/unit/storage.rb +5 -3
- data/lib/flor/unit/waiter.rb +12 -2
- data/lib/flor/unit/wlist.rb +4 -3
- data/match.md +22 -0
- metadata +15 -5
- data/lib/flor/pcore/_happly.rb +0 -49
- data/lib/flor/pcore/val.rb +0 -16
- data/t.txt +0 -4
data/lib/flor/pcore/_arr.rb
CHANGED
@@ -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
|
|
data/lib/flor/pcore/_atom.rb
CHANGED
@@ -6,11 +6,12 @@ class Flor::Pro::Atom < Flor::Procedure
|
|
6
6
|
def execute
|
7
7
|
|
8
8
|
payload['ret'] =
|
9
|
-
case
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
data/lib/flor/pcore/_att.rb
CHANGED
@@ -121,12 +121,17 @@ class Flor::Pro::Att < Flor::Procedure
|
|
121
121
|
wrap_reply
|
122
122
|
end
|
123
123
|
|
124
|
-
def
|
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
|
-
|
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)
|
data/lib/flor/pcore/_obj.rb
CHANGED
@@ -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
|
28
|
+
def execute_child(index=0, sub=nil, h=nil)
|
13
29
|
|
14
|
-
return
|
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
|
-
|
32
|
+
return super if @node['rets'].size.odd?
|
32
33
|
|
33
|
-
|
34
|
+
ct = children[index]
|
35
|
+
q = (att('quote') == 'keys')
|
34
36
|
|
35
|
-
|
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
|
-
|
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
|
-
|
47
|
-
|
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
|
+
|