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
@@ -0,0 +1,46 @@
1
+
2
+ require 'flor/pcore/_pat_'
3
+
4
+
5
+ class Flor::Pro::PatOr < Flor::Pro::PatContainer
6
+
7
+ name '_pat_or'
8
+
9
+ def pre_execute
10
+
11
+ unatt_unkeyed_children
12
+ end
13
+
14
+ def receive_non_att
15
+
16
+ ct = child_type(@fcid)
17
+
18
+ if ct == :pattern
19
+
20
+ b = payload.delete('_pat_binding')
21
+ return wrap_match_reply(b) if b
22
+
23
+ elsif payload['ret'] == val
24
+
25
+ return wrap_match_reply({})
26
+ end
27
+
28
+ super
29
+ end
30
+
31
+ def receive_last
32
+
33
+ wrap_no_match_reply
34
+ end
35
+
36
+ protected
37
+
38
+ def wrap_match_reply(binding)
39
+
40
+ payload['_pat_binding'] = binding
41
+ payload.delete('_pat_val')
42
+
43
+ wrap_reply
44
+ end
45
+ end
46
+
@@ -0,0 +1,20 @@
1
+
2
+ class Flor::Pro::Val < Flor::Procedure
3
+
4
+ name '_val'
5
+
6
+ def wrap_reply
7
+
8
+ if node_open?
9
+
10
+ heat = @node['heat']
11
+ #heat = nil if heat == [ '_proc', 'val', -1 ] || heat[0] == '_nul'
12
+ heat = nil if heat[0] == '_nul'
13
+
14
+ payload['ret'] = heat
15
+ end
16
+
17
+ super
18
+ end
19
+ end
20
+
@@ -1,7 +1,7 @@
1
1
 
2
2
  class Flor::Pro::Arith < Flor::Procedure
3
3
 
4
- names %w[ + - * / ]
4
+ names %w[ + - * / % ]
5
5
 
6
6
  DEFAULTS = { :+ => 0, :* => 1, :- => 0, :/ => 1 }
7
7
 
@@ -13,6 +13,12 @@ class Flor::Pro::Arith < Flor::Procedure
13
13
  def receive_last
14
14
 
15
15
  sign = tree.first.to_sym
16
+ count = @node['rets'].size
17
+
18
+ if sign == :% && count < 2
19
+ fail ArgumentError.new(
20
+ "modulo % requires at least 2 arguments (line #{tree[2]})")
21
+ end
16
22
 
17
23
  payload['ret'] = @node['rets'].reduce(&sign) || DEFAULTS[sign]
18
24
 
@@ -9,11 +9,11 @@ class Flor::Pro::Case < Flor::Procedure
9
9
  #
10
10
  # ```
11
11
  # case level
12
- # [ 0 1 2 ];; 'low'
13
- # [ 3 4 5 ];; 'medium'
14
- # else;; 'high'
12
+ # [ 0 1 2 ]; 'low'
13
+ # [ 3 4 5 ]; 'medium'
14
+ # else; 'high'
15
15
  # ```
16
- # which is a ";;"ed version of
16
+ # which is a ";"ed version of
17
17
  # ```
18
18
  # case level
19
19
  # [ 0 1 2 ]
@@ -37,89 +37,66 @@ class Flor::Pro::Case < Flor::Procedure
37
37
  def pre_execute
38
38
 
39
39
  unatt_unkeyed_children
40
- # flatten
40
+
41
+ @node['val'] = payload['ret'] if non_att_children.size.even?
41
42
  end
42
43
 
43
- def receive_non_att
44
+ def receive
44
45
 
45
46
  return wrap_reply if @node['found']
46
47
 
47
- return receive_array if @node.has_key?('key')
48
+ determine_fcid_and_ncid
49
+
50
+ return execute_child(@ncid) if @fcid == nil
51
+
52
+ has_no_val = ! @node.has_key?('val')
48
53
 
49
- @node['key'] = payload['ret']
50
- super
54
+ if has_no_val && ! from_att?
55
+ @node['val'] = payload['ret']
56
+ execute_conditional
57
+ elsif has_no_val
58
+ execute_child(@ncid)
59
+ elsif m = match?
60
+ execute_then(@ncid, m)
61
+ else
62
+ execute_conditional(@ncid + 1)
63
+ end
51
64
  end
52
65
 
53
66
  protected
54
67
 
55
- def receive_array
68
+ def execute_conditional(ncid=@ncid)
56
69
 
57
- a = payload['ret']
58
- a = a.nil? ? [ a ] : Array(a)
70
+ if else?(ncid)
71
+ execute_then(ncid + 1)
72
+ else
73
+ payload['ret'] = node_payload_ret
74
+ execute_child(ncid)
75
+ end
76
+ end
59
77
 
60
- payload['ret'] = node_payload_ret
78
+ def execute_then(ncid, vars=nil)
61
79
 
62
- if a.include?(@node['key'])
80
+ payload['ret'] = node_payload_ret
81
+ @node['found'] = true
63
82
 
64
- @node['found'] = true
65
- execute_child(@fcid + 1)
83
+ h = vars.is_a?(Hash) ? { 'vars' => vars } : nil
66
84
 
67
- else
85
+ execute_child(ncid, nil, h)
86
+ end
68
87
 
69
- t = tree[1][@fcid + 2]
88
+ def else?(ncid)
70
89
 
71
- if t && t[0, 2] == [ 'else', [] ]
72
- @node['found'] = true
73
- execute_child(@fcid + 3)
74
- else
75
- execute_child(@fcid + 2)
76
- end
77
- end
90
+ (t = tree[1][ncid]) &&
91
+ t[0, 2] == [ 'else', [] ]
78
92
  end
79
93
 
80
- # def flatten
81
- #
82
- # ot = tree; return if ot[1].size < 2
83
- # t = Flor.dup(ot)
84
- #
85
- # nchildren = []
86
- # mode = :array
87
- #
88
- # #t[1][1..-1].each do |ct|
89
- # non_att_children.each do |ct|
90
- #
91
- # if nchildren.empty? || mode == :clause
92
- # nchildren << ct
93
- # mode = :array
94
- # next
95
- # end
96
- #
97
- # ct0, ct1, ct2 = ct
98
- #
99
- # if (Flor.is_tree?(ct0) || ct0 == 'else') && ct1.any?
100
- # nchildren << (ct0 == 'else' ? [ 'else', [], ct2 ] : ct0)
101
- # if ct1.size == 1
102
- # nchildren << ct1.first
103
- # else # ct1.size > 1
104
- # sequence = [ 'sequence', ct1, ct1.first[2] ]
105
- # nchildren << sequence
106
- # end
107
- # #elsif ct0.is_a?(String) && ct1.is_a?(Array) && ct1.any?
108
- # # p ct
109
- # # dct0 = deref(ct0)
110
- # # hct0 = reheap(ct, dct0)
111
- # # p dct0
112
- # # p hct0
113
- # else
114
- # nchildren << ct
115
- # mode = :clause
116
- # end
117
- # end
118
- #
119
- # t[1] = nchildren
120
- #pp nchildren
121
- #
122
- # @node['tree'] = t if t != ot
123
- # end
94
+ def match?
95
+
96
+ a = payload['ret']
97
+ a = a.nil? ? [ a ] : Array(a)
98
+
99
+ a.include?(@node['val'])
100
+ end
124
101
  end
125
102
 
@@ -132,20 +132,27 @@ class Flor::Pro::Cursor < Flor::Procedure
132
132
  fail("move target #{to.inspect} not found")
133
133
  end
134
134
 
135
+ def is_tag_tree?(t, tagname)
136
+
137
+ Flor.is_att_tree?(t) &&
138
+ t[1].size == 2 &&
139
+ t[1][0][0, 2] == [ 'tag', [] ] &&
140
+ Flor.is_string_tree?(t[1][1], tagname)
141
+ end
142
+
143
+ def is_att_string_tree?(t, s)
144
+
145
+ Flor.is_att_tree?(t) &&
146
+ t[1].size == 1 &&
147
+ Flor.is_string_tree?(t[1].first, s)
148
+ end
149
+
135
150
  def find_tag_target(to)
136
151
 
137
152
  tree[1]
138
- .index { |c|
139
- c[1].is_a?(Array) &&
140
- c[1].index { |cc|
141
- Flor.is_tree?(cc) &&
142
- cc[0] == '_att' &&
143
- cc[1].size == 2 &&
144
- cc[1][0][0] == 'tag' &&
145
- %w[ _sqs _dqs ].include?(cc[1][1][0]) &&
146
- cc[1][1][1] == to
147
- }
148
- }
153
+ .index { |ct|
154
+ ct[1].is_a?(Array) &&
155
+ ct[1].index { |cc| is_tag_tree?(cc, to) } }
149
156
  end
150
157
 
151
158
  def find_string_arg_target(to)
@@ -153,24 +160,19 @@ class Flor::Pro::Cursor < Flor::Procedure
153
160
  tree[1]
154
161
  .index { |c|
155
162
  c[1].is_a?(Array) &&
156
- c[1].index { |cc|
157
- Flor.is_tree?(cc) &&
158
- cc[0] == '_att' &&
159
- cc[1].size == 1 &&
160
- %w[ _sqs _dqs ].include?(cc[1][0][0]) &&
161
- cc[1][0][1] == to
162
- }
163
- }
163
+ c[1].index { |cc| is_att_string_tree?(cc, to) } }
164
164
  end
165
165
 
166
166
  def find_string_target(to)
167
167
 
168
- tree[1].index { |c| %w[ _sqs _dqs ].include?(c[0]) && c[1] == to }
168
+ tree[1]
169
+ .index { |ct| Flor.is_string_tree?(ct, to) }
169
170
  end
170
171
 
171
172
  def find_name_target(to)
172
173
 
173
- tree[1].index { |c| c[0] == to }
174
+ tree[1]
175
+ .index { |ct| ct[0] == to }
174
176
  end
175
177
 
176
178
  def find_att_target(to)
@@ -182,9 +184,7 @@ class Flor::Pro::Cursor < Flor::Procedure
182
184
  c[1].find { |cc|
183
185
  cc[0] == '_att' &&
184
186
  cc[1].is_a?(Array) &&
185
- cc[1][0][0, 2] == [ 'here', [] ]
186
- }
187
- }
187
+ cc[1][0][0, 2] == [ 'here', [] ] } } # FIXME hardcoded...
188
188
  end
189
189
  end
190
190
 
@@ -50,9 +50,13 @@ class Flor::Pro::Define < Flor::Procedure
50
50
  cnode = lookup_var_node(@node, 'l')
51
51
  cnid = cnode['nid']
52
52
  fun = counter_next('funs') - 1
53
+
53
54
  (cnode['closures'] ||= []) << fun
54
55
 
55
- val = [ '_func', { 'nid' => nid, 'cnid' => cnid, 'fun' => fun }, t[2] ]
56
+ val = [
57
+ '_func',
58
+ { 'nid' => nid, 'tree' => t, 'cnid' => cnid, 'fun' => fun },
59
+ t[2] ]
56
60
 
57
61
  if t[0] == 'define'
58
62
  name =
@@ -0,0 +1,32 @@
1
+
2
+ class Flor::Pro::DoReturn < Flor::Macro
3
+ #
4
+ # Takes a set of arguments and returns a function
5
+ # that will return those arguments again.
6
+ #
7
+ # ```
8
+ # set a
9
+ # do-return 1
10
+ # a _
11
+ # ```
12
+ # will set 1 in the payload `ret`.
13
+ #
14
+ # It might be useful in cases like:
15
+ # ```
16
+ # sequence on_error: (do-return 1)
17
+ # do-this-failure-prone-thing _
18
+ # ```
19
+ #
20
+
21
+ name 'do-return'
22
+
23
+ def rewrite_tree
24
+
25
+ l = tree[2]
26
+
27
+ [ 'sequence', [
28
+ [ 'def', att_children.first[1], l ]
29
+ ], l ]
30
+ end
31
+ end
32
+
@@ -0,0 +1,18 @@
1
+
2
+ class Flor::Pro::Length < Flor::Procedure
3
+
4
+ name 'length'
5
+
6
+ def receive_last
7
+
8
+ r = payload['ret']
9
+
10
+ payload['ret'] =
11
+ if r.respond_to?(:length) then r.length
12
+ else -1
13
+ end
14
+
15
+ super
16
+ end
17
+ end
18
+
@@ -0,0 +1,47 @@
1
+
2
+ class Flor::Pro::Logo < Flor::Procedure
3
+
4
+ names %w[ and or ]
5
+
6
+ def execute
7
+
8
+ payload['ret'] = @node['heat0'] == 'and'
9
+
10
+ super
11
+ end
12
+
13
+ def receive_att
14
+
15
+ c = children[@fcid]; return super if c[0] == '_att' && [1].size == 2
16
+
17
+ h0 = @node['heat0']
18
+
19
+ ret = Flor.true?(payload['ret'])
20
+
21
+ return wrap_reply if ((h0 == 'or' && ret) || (h0 == 'and' && ! ret))
22
+
23
+ super
24
+ end
25
+
26
+ alias receive_non_att receive_att
27
+
28
+ # def pre_execute
29
+ #
30
+ # @node['rets'] = []
31
+ # end
32
+ #
33
+ # def receive_last
34
+ #
35
+ # payload['ret'] =
36
+ # if @node['heat0'] == 'or'
37
+ # !! @node['rets'].index { |r| Flor.true?(r) }
38
+ # else
39
+ # ! @node['rets'].index { |r| Flor.false?(r) }
40
+ # end
41
+ #
42
+ # wrap_reply
43
+ # end
44
+ #
45
+ # Keep me around for a "aand" and a "oor"... Maybe...
46
+ end
47
+
@@ -1,19 +1,17 @@
1
1
 
2
2
  class Flor::Pro::Map < Flor::Procedure
3
3
 
4
- name 'map'
4
+ names %w[ map for-each ]
5
5
 
6
6
  def pre_execute
7
7
 
8
- #@node['ret'] = Flor.dup(payload['ret']) # now using @node['payload']
9
-
10
- @node['vars'] = {}
11
- # just to store the local idx
8
+ @node['vars'] ||= {}
12
9
 
13
10
  @node['col'] = nil
14
11
  @node['idx'] = -1
15
12
  @node['fun'] = nil
16
- @node['res'] = []
13
+
14
+ @node['res'] = @node['heat0'] == 'map' ? [] : nil
17
15
 
18
16
  unatt_unkeyed_children
19
17
  end
@@ -33,15 +31,19 @@ class Flor::Pro::Map < Flor::Procedure
33
31
 
34
32
  if @node['idx'] < 0
35
33
  @node['fun'] = payload['ret']
36
- else
37
- @node['res'] << payload['ret']
34
+ elsif res = @node['res']
35
+ res << payload['ret']
38
36
  end
39
37
 
40
38
  @node['idx'] += 1
41
39
  @node['mtime'] = Flor.tstamp
42
40
 
43
- return wrap_reply('ret' => @node['res']) \
44
- if @node['idx'] == @node['col'].size
41
+ if @node['idx'] == @node['col'].size
42
+ if res = @node['res']
43
+ payload['ret'] = @node['res']
44
+ end
45
+ return wrap_reply
46
+ end
45
47
 
46
48
  @node['vars']['idx'] = @node['idx']
47
49