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