flor 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|