atomy 0.1.1

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 (99) hide show
  1. data/COPYING +30 -0
  2. data/README.md +1 -0
  3. data/bin/atomy +134 -0
  4. data/kernel/block.ay +30 -0
  5. data/kernel/boot.ay +10 -0
  6. data/kernel/comparison.ay +61 -0
  7. data/kernel/concurrency.ay +84 -0
  8. data/kernel/condition.ay +277 -0
  9. data/kernel/control-flow.ay +222 -0
  10. data/kernel/cosmetics.ay +3 -0
  11. data/kernel/data-delta.ay +105 -0
  12. data/kernel/data.ay +56 -0
  13. data/kernel/define.ay +93 -0
  14. data/kernel/doc.ay +453 -0
  15. data/kernel/documentation.ay +135 -0
  16. data/kernel/dynamic.ay +42 -0
  17. data/kernel/errors.ay +6 -0
  18. data/kernel/format.ay +13 -0
  19. data/kernel/format/data.ay +89 -0
  20. data/kernel/format/formatter.ay +345 -0
  21. data/kernel/format/parser.ay +13 -0
  22. data/kernel/hashes.ay +39 -0
  23. data/kernel/io.ay +244 -0
  24. data/kernel/namespaces.ay +63 -0
  25. data/kernel/node.ay +48 -0
  26. data/kernel/operators.ay +28 -0
  27. data/kernel/particles.ay +53 -0
  28. data/kernel/patterns.ay +256 -0
  29. data/kernel/precision.ay +148 -0
  30. data/kernel/pretty.ay +283 -0
  31. data/kernel/repl.ay +140 -0
  32. data/kernel/therie.ay +204 -0
  33. data/lib/ast/binary_send.rb +44 -0
  34. data/lib/ast/block.rb +268 -0
  35. data/lib/ast/constant.rb +88 -0
  36. data/lib/ast/internal/assign.rb +19 -0
  37. data/lib/ast/internal/block_pass.rb +21 -0
  38. data/lib/ast/internal/catch.rb +247 -0
  39. data/lib/ast/internal/class.rb +30 -0
  40. data/lib/ast/internal/class_variable.rb +23 -0
  41. data/lib/ast/internal/define.rb +174 -0
  42. data/lib/ast/internal/ensure.rb +135 -0
  43. data/lib/ast/internal/file.rb +14 -0
  44. data/lib/ast/internal/global_variable.rb +20 -0
  45. data/lib/ast/internal/if_then_else.rb +24 -0
  46. data/lib/ast/internal/instance_variable.rb +17 -0
  47. data/lib/ast/internal/let_macro.rb +35 -0
  48. data/lib/ast/internal/macro_quote.rb +23 -0
  49. data/lib/ast/internal/match.rb +53 -0
  50. data/lib/ast/internal/module.rb +30 -0
  51. data/lib/ast/internal/pattern.rb +17 -0
  52. data/lib/ast/internal/return.rb +29 -0
  53. data/lib/ast/internal/set.rb +19 -0
  54. data/lib/ast/internal/singleton_class.rb +18 -0
  55. data/lib/ast/internal/splat.rb +14 -0
  56. data/lib/ast/internal/when.rb +24 -0
  57. data/lib/ast/list.rb +25 -0
  58. data/lib/ast/macro.rb +37 -0
  59. data/lib/ast/node.rb +599 -0
  60. data/lib/ast/operator.rb +21 -0
  61. data/lib/ast/particle.rb +13 -0
  62. data/lib/ast/primitive.rb +20 -0
  63. data/lib/ast/quasi_quote.rb +20 -0
  64. data/lib/ast/quote.rb +13 -0
  65. data/lib/ast/send.rb +104 -0
  66. data/lib/ast/splice.rb +32 -0
  67. data/lib/ast/string.rb +23 -0
  68. data/lib/ast/unary.rb +44 -0
  69. data/lib/ast/unquote.rb +45 -0
  70. data/lib/ast/variable.rb +64 -0
  71. data/lib/atomy.kpeg.rb +3995 -0
  72. data/lib/code_loader.rb +137 -0
  73. data/lib/compiler/compiler.rb +155 -0
  74. data/lib/compiler/stages.rb +81 -0
  75. data/lib/formatter.kpeg.rb +1394 -0
  76. data/lib/macros.rb +317 -0
  77. data/lib/method.rb +261 -0
  78. data/lib/namespace.rb +236 -0
  79. data/lib/parser.rb +28 -0
  80. data/lib/patterns.rb +276 -0
  81. data/lib/patterns/any.rb +21 -0
  82. data/lib/patterns/attribute.rb +59 -0
  83. data/lib/patterns/block_pass.rb +54 -0
  84. data/lib/patterns/constant.rb +33 -0
  85. data/lib/patterns/default.rb +44 -0
  86. data/lib/patterns/head_tail.rb +63 -0
  87. data/lib/patterns/list.rb +77 -0
  88. data/lib/patterns/match.rb +45 -0
  89. data/lib/patterns/named.rb +55 -0
  90. data/lib/patterns/named_class.rb +46 -0
  91. data/lib/patterns/named_global.rb +46 -0
  92. data/lib/patterns/named_instance.rb +46 -0
  93. data/lib/patterns/particle.rb +29 -0
  94. data/lib/patterns/quasi_quote.rb +184 -0
  95. data/lib/patterns/quote.rb +33 -0
  96. data/lib/patterns/singleton_class.rb +31 -0
  97. data/lib/patterns/splat.rb +57 -0
  98. data/lib/util.rb +37 -0
  99. metadata +164 -0
data/kernel/repl.ay ADDED
@@ -0,0 +1,140 @@
1
+ namespace(atomy)
2
+
3
+ title"The REPL"
4
+
5
+ require("readline")
6
+
7
+ doc"
8
+ The basics of a REPL - reading, evaluating, and printing in a loop. More \
9
+ flexibility is provided by various signals. See \hl{repl} for a fancier \
10
+ REPL, which builds upon this, and \hl{ReplDebugger}.
11
+
12
+ When showing the prompt, \hl{#prompt} is signaled with a \hl{#use-prompt} \
13
+ restart available. Invoke this restart and pass along a string to \
14
+ override the prompt, which defaults to \code{>>}.
15
+
16
+ Input preceded by a colon (\code{:}) and followed by an alphanumeric \
17
+ character is assumed to be a \italic{special command}. These are not \
18
+ evaluated, and are signaled as \hl{#special(\italic{text})}.
19
+
20
+ When the user sends \code{EOF} (Ctrl+D) or an interrupt (Ctrl+C), \
21
+ \hl{#quit} is signaled.
22
+
23
+ When the user enters code, \hl{#input(\italic{text})} is signaled. The code\
24
+ is evaluated with two restarts registered: \code{#retry} for re-attempting \
25
+ evaluation, and \code{#abort}, for canceling the evaluation. After the code\
26
+ is evaluated, \hl{#evaluated(\italic{result})} is signaled.
27
+
28
+ \hl{#loop} is signaled before the loop starts over again (i.e., after the \
29
+ input is handled).
30
+ " spec {
31
+ bnd is-a?(Binding)
32
+ } for:
33
+ basic-repl(bnd = TOPLEVEL_BINDING) :=
34
+ loop:
35
+ prompt =
36
+ with-restarts(use-prompt(p) -> p):
37
+ signal(#prompt)
38
+ ">> "
39
+
40
+ in =
41
+ { Readline readline(prompt)
42
+ } rescue:
43
+ Interrupt -> do { signal(#quit), "" }
44
+
45
+ in match:
46
+ nil -> signal(#quit)
47
+
48
+ "" -> #ok
49
+
50
+ String ? (=~ r"^:[[:alnum:]]") ->
51
+ signal(#special(in [1 .. -1]))
52
+
53
+ source -> do:
54
+ signal(#input(source))
55
+
56
+ try = {
57
+ with-restarts(retry -> try [], abort -> #ok):
58
+ res = Atomy::Compiler evaluate(source, bnd)
59
+ signal(#evaluated(res))
60
+ }
61
+
62
+ try []
63
+
64
+ signal(#loop)
65
+
66
+
67
+ doc"
68
+ An interactive debugger REPL for handling errors. This will list the \
69
+ results along with a number, allow the user to continue evaluating code, \
70
+ and once they enter a \italic{special command} in the form of \
71
+ \code{:\italic{number}}, the specified restart will be invoked.
72
+ " for:
73
+ class(ReplDebugger):
74
+ class(<< self):
75
+ show-backtrace(e) := do:
76
+ Rubinius::Backtrace backtrace(e backtrace) _/show print
77
+ debug(e)
78
+
79
+ run(e) := do:
80
+ DefaultDebugger show-error-banner(e)
81
+
82
+ with-restarts(backtrace -> show-backtrace(e)):
83
+ debug(e)
84
+
85
+ debug(e) := do:
86
+ DefaultDebugger show-options-for(e)
87
+
88
+ { basic-repl } bind:
89
+ #prompt -> restart(#use-prompt, "[!]> ")
90
+
91
+ #special(n ? (=~ r"\d+")) ->
92
+ ^restarts [n to-i] invoke
93
+
94
+ #quit -> exit(1)
95
+
96
+ dynamic(debugger, ReplDebugger)
97
+
98
+ doc"
99
+ A more feature-filled REPL, providing persistent history and setting \
100
+ \hl{^debugger} to \hl{ReplDebugger}.
101
+
102
+ History will be managed and appended to a file specified by \hl{history} \
103
+ upon termination.
104
+ " spec {
105
+ history is-a?(String)
106
+ bnd is-a?(Binding)
107
+ } for:
108
+ repl(history = nil, bnd = TOPLEVEL_BINDING) := do:
109
+ when(history && File exists?(history)):
110
+ File open(history, "r") [f]:
111
+ f readlines each [l]:
112
+ Readline::HISTORY << l strip
113
+
114
+ SANE_HISTORY = []
115
+
116
+ { let(debugger = ReplDebugger):
117
+ frame = 0
118
+
119
+ { let(atomy/pretty/colored? = true):
120
+ basic-repl(bnd)
121
+ } bind:
122
+ #prompt ->
123
+ restart(#use-prompt, "[" + frame to-s + "]> ")
124
+
125
+ #loop ->
126
+ (frame += 1)
127
+
128
+ #quit -> exit(0)
129
+
130
+ #input(str) -> (SANE_HISTORY << str)
131
+
132
+ #special("h") ->
133
+ ":h\thelp" print
134
+
135
+ #evaluated(r) ->
136
+ (" => " + r show) print
137
+ } ensuring:
138
+ when(history):
139
+ File open(history, "a") [f]:
140
+ f puts(*SANE_HISTORY)
data/kernel/therie.ay ADDED
@@ -0,0 +1,204 @@
1
+ namespace(therie)
2
+
3
+ title"Testing with Therie"
4
+
5
+ doc"
6
+ Therie is a small and simple behavioral-style testing suite that comes with \
7
+ Atomy. To use it, you should use the \hl{therie} namespace, which provides \
8
+ the following methods.
9
+
10
+ \atomy{
11
+ use(therie)
12
+ }
13
+ "
14
+
15
+ dynamic(nesting-level, 0)
16
+
17
+ doc"
18
+ A trivial container of \hl{passed} and \hl{failed} counts, with accessors \
19
+ for both.
20
+ " for:
21
+ class(Stats):
22
+ attr-accessor(#passed, #failed)
23
+
24
+ export:
25
+ initialize := do:
26
+ @passed = 0
27
+ @failed = 0
28
+
29
+ inspect := f"Stats(@passed = %d, @failed = %d)" [@passed, @failed]
30
+
31
+ dynamic(stats, nil)
32
+
33
+
34
+ section("Structure"):
35
+ doc"\evaluate{use(therie)}"
36
+
37
+ doc"
38
+ Run \hl{tests} and keep track of how many passed and how many failed, \
39
+ printing the stats at the end and returning them.
40
+ " spec {
41
+ => Stats
42
+ } for {
43
+ theorize(&tests) :=
44
+ let(stats = Stats new):
45
+ tests call
46
+ "\n" display
47
+
48
+ ^stats onto:
49
+ f"total of %d tests (%s passed, %s failed)" [
50
+ failed + passed
51
+ passed to-s colored(#green)
52
+ if(failed == 0)
53
+ then: "0"
54
+ else: failed to-s colored(#red)
55
+ ] display
56
+
57
+ "\n" display
58
+
59
+ ^stats
60
+ } examples:
61
+ theorize:
62
+ describe("foo"):
63
+ it("does x"): true should-be(false)
64
+ it("does x"): true should-be(true)
65
+
66
+
67
+ doc"
68
+ Logically group together a set of behavior.
69
+
70
+ Prints out \hl{what}, with each test in \hl{body} indented afterward.
71
+ " for {
72
+ describe(what, &body) := do:
73
+ f"- %s" [what] indented print
74
+
75
+ let(nesting-level = ^nesting-level + 1):
76
+ body call
77
+
78
+ nil
79
+ } examples:
80
+ describe("foo"):
81
+ it("does x"): true should-be(false)
82
+ it("does x"): true should-be(true)
83
+
84
+
85
+ doc"
86
+ Describe some behavior that the tests in \hl{body} will demonstrate.
87
+ " for {
88
+ it(description, &tests) := do:
89
+ { tests call
90
+ f"✓ %s" [description] indented colored(#green) print
91
+ } rescue {
92
+ e -> do:
93
+ when(^stats):
94
+ ^stats failed += 1
95
+
96
+ f"✗ %s" [description] indented colored(#red) print
97
+ f" ` %s: %s" [
98
+ e class name
99
+ e message
100
+ ] indented colored(#yellow) print
101
+
102
+ e backtrace first(5) each [l]:
103
+ f" %s" [l colored(#cyan)] indented print
104
+ } else:
105
+ when(^stats):
106
+ ^stats passed += 1
107
+
108
+ nil
109
+ } examples:
110
+ it("adds correctly"): (2 + 2) should-be(4)
111
+ it("adds correctly"): (1 + 2) should-be(4)
112
+
113
+
114
+ section("Tests"):
115
+ doc"\evaluate{use(therie)}"
116
+
117
+ doc"
118
+ Test that \hl{predicate} is satisified by \hl{o} by evaluating it with \
119
+ \hl{o} as \hl{self}.
120
+ " for {
121
+ o should(&check) :=
122
+ unless(o onto(&check)):
123
+ raise(f"assertion failed for %v" [o])
124
+ } examples:
125
+ (2 + 2) should: even?
126
+ (2 + 2) should: odd?
127
+
128
+
129
+ doc"
130
+ Test for \hl{x == y}.
131
+ " for {
132
+ x should-be(y) :=
133
+ unless(x == y):
134
+ raise(f"expected %v, got %v" [y, x])
135
+ } examples:
136
+ (2 + 2) should-be(4)
137
+ (1 + 2) should-be(4)
138
+
139
+
140
+ doc"
141
+ Test that executing \hl{x} will raise an exception of class \hl{y}.
142
+ " spec {
143
+ x respond-to?(#call)
144
+ y is-a?(Class)
145
+ } for {
146
+ x should-raise(y) :=
147
+ x rescue {
148
+ e ->
149
+ unless(e kind-of?(y)):
150
+ raise(f"expected exception %s, got: %s" [y, e])
151
+ } else:
152
+ raise("#should-raise - no exception raised")
153
+ } examples:
154
+ { abc } should-raise(NoMethodError)
155
+ { #ok } should-raise(NoMethodError)
156
+
157
+
158
+ doc"
159
+ Test that executing \hl{x} will signal an error of class \hl{y}.
160
+ " spec {
161
+ x respond-to?(#call)
162
+ y is-a?(Class)
163
+ } for {
164
+ x should-error(y) :=
165
+ { with-restarts(errored -> nil):
166
+ x call
167
+ raise("#should-error - no error signaled")
168
+ } bind {
169
+ (e: ExceptionError) ->
170
+ raise(e exception)
171
+
172
+ (e: Error) -> do:
173
+ when(e kind-of?(y)):
174
+ restart(#errored)
175
+
176
+ raise(f"expected error %s, got: %s" [y, e message])
177
+ }
178
+ } examples:
179
+ { error(#foo) } should-error(SimpleError)
180
+ { #ok } should-error(SimpleError)
181
+
182
+
183
+ -- helpers
184
+ String indented := " " * (^nesting-level * 2) + self
185
+
186
+ String colored(color) := do:
187
+ -- only makes sense to colorize if we're outputting to a terminal
188
+ unless(^output-port tty?):
189
+ return(self)
190
+
191
+ codes =
192
+ [ #black
193
+ #red
194
+ #green
195
+ #yellow
196
+ #blue
197
+ #magenta
198
+ #cyan
199
+ #white
200
+ ] zip((0 .. 7) to-a)
201
+
202
+ hash = Hash [codes]
203
+
204
+ "\e[9" + hash [color] to-s + "m" + self + "\e[0m"
@@ -0,0 +1,44 @@
1
+ module Atomy
2
+ module AST
3
+ class BinarySend < Node
4
+ children :lhs, :rhs
5
+ attributes :operator
6
+ slots [:private, "false"], :namespace?
7
+ generate
8
+
9
+ alias :method_name :operator
10
+
11
+ def register_macro(body, let = false)
12
+ Atomy::Macro.register(
13
+ @operator,
14
+ [@lhs, @rhs].collect do |n|
15
+ Atomy::Macro.macro_pattern n
16
+ end,
17
+ body,
18
+ let
19
+ )
20
+ end
21
+
22
+ def message_name
23
+ Atomy.namespaced(@namespace, @operator)
24
+ end
25
+
26
+ def prepare
27
+ resolve.expand
28
+ end
29
+
30
+ def bytecode(g)
31
+ pos(g)
32
+ @lhs.compile(g)
33
+ g.push_literal message_name.to_sym unless @namespace == "_"
34
+ @rhs.compile(g)
35
+ if @namespace == "_"
36
+ g.send @operator.to_sym, 1
37
+ else
38
+ g.send :atomy_send, 2
39
+ #g.call_custom method_name.to_sym, 1
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
data/lib/ast/block.rb ADDED
@@ -0,0 +1,268 @@
1
+ module Atomy
2
+ module AST
3
+ class Block < Rubinius::AST::Iter
4
+ include NodeLike
5
+ extend SentientNode
6
+
7
+ children [:contents], [:arguments]
8
+ generate
9
+
10
+ def block_arguments
11
+ BlockArguments.new @arguments
12
+ end
13
+
14
+ def block_body
15
+ BlockBody.new @line, @contents
16
+ end
17
+
18
+ def body
19
+ InlinedBody.new @line, @contents
20
+ end
21
+
22
+ alias :caller :body
23
+
24
+ def bytecode(g)
25
+ pos(g)
26
+
27
+ state = g.state
28
+ state.scope.nest_scope self
29
+
30
+ blk = new_block_generator g, block_arguments
31
+
32
+ blk.push_state self
33
+ blk.state.push_super state.super
34
+ blk.state.push_eval state.eval
35
+
36
+ blk.state.push_name blk.name
37
+
38
+ # Push line info down.
39
+ pos(blk)
40
+
41
+ block_arguments.bytecode(blk)
42
+
43
+ blk.state.push_block
44
+ blk.push_modifiers
45
+ blk.break = nil
46
+ blk.next = nil
47
+ blk.redo = blk.new_label
48
+ blk.redo.set!
49
+
50
+ block_body.compile(blk)
51
+
52
+ blk.pop_modifiers
53
+ blk.state.pop_block
54
+ blk.ret
55
+ blk.close
56
+ blk.pop_state
57
+
58
+ blk.splat_index = block_arguments.splat_index
59
+ blk.local_count = local_count
60
+ blk.local_names = local_names
61
+
62
+ g.create_block blk
63
+
64
+ g.push_cpath_top
65
+ g.find_const :Proc
66
+ g.swap
67
+ g.send :__from_block__, 1
68
+ end
69
+
70
+ def as_message(send)
71
+ case send.receiver
72
+ when Send
73
+ if send.receiver.method_name == "[]"
74
+ dup.tap do |b|
75
+ b.arguments = send.receiver.arguments
76
+ end.as_message(send.receiver)
77
+ else
78
+ send.receiver.dup.tap do |s|
79
+ s.block = self
80
+ end
81
+ end
82
+ when Variable, Unquote,
83
+ Constant, ScopedConstant, ToplevelConstant
84
+ send.receiver = send.receiver.to_send
85
+ as_message(send)
86
+ when List
87
+ dup.tap do |b|
88
+ b.arguments = send.receiver.elements
89
+ end
90
+ else
91
+ unless send.method_name
92
+ raise "unknown receiver for block: #{send.receiver.inspect}"
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ class InlinedBody < Node
99
+ children [:expressions]
100
+ generate
101
+
102
+ attr_accessor :parent
103
+
104
+ def variables
105
+ @variables ||= {}
106
+ end
107
+
108
+ def local_count
109
+ @parent.local_names
110
+ end
111
+
112
+ def local_names
113
+ @parent.local_names
114
+ end
115
+
116
+ def allocate_slot
117
+ @parent.allocate_slot
118
+ end
119
+
120
+ def nest_scope(scope)
121
+ scope.parent = self
122
+ end
123
+
124
+ def search_local(name)
125
+ if variable = variables[name]
126
+ variable.nested_reference
127
+ else
128
+ @parent.search_local(name)
129
+ end
130
+ end
131
+
132
+ def pseudo_local(name)
133
+ if variable = variables[name]
134
+ variable.nested_reference
135
+ elsif reference = @parent.search_local(name)
136
+ reference.depth += 1
137
+ reference
138
+ end
139
+ end
140
+
141
+ def new_local(name)
142
+ variables[name] =
143
+ @parent.new_local(name + ":" + @parent.allocate_slot.to_s)
144
+ end
145
+
146
+ def new_nested_local(name)
147
+ @parent.new_local(name).nested_reference
148
+ end
149
+
150
+ def empty?
151
+ @expressions.empty?
152
+ end
153
+
154
+ def setup(g)
155
+ g.state.scope.nest_scope self
156
+
157
+ blk = g.state.block?
158
+ ens = g.state.ensure?
159
+ res = g.state.rescue?
160
+ lop = g.state.loop?
161
+ msn = g.state.masgn?
162
+
163
+ g.push_state self
164
+
165
+ g.state.push_block if blk
166
+ g.state.push_ensure if ens
167
+ g.state.push_rescue(res) if res
168
+ g.state.push_loop if lop
169
+ g.state.push_masgn if msn
170
+ end
171
+
172
+ def reset(g)
173
+ g.pop_state
174
+ end
175
+
176
+ def bytecode(g)
177
+ pos(g)
178
+
179
+ setup(g)
180
+
181
+ g.push_nil if empty?
182
+
183
+ @expressions.each_with_index do |node,idx|
184
+ g.pop unless idx == 0
185
+ node.compile(g)
186
+ end
187
+
188
+ reset(g)
189
+ end
190
+ end
191
+
192
+ class BlockArguments
193
+ attr_reader :arguments
194
+
195
+ def initialize(args)
196
+ @arguments = args.collect(&:to_pattern)
197
+ end
198
+
199
+ def bytecode(g)
200
+ return if @arguments.empty?
201
+
202
+ if @arguments.last.kind_of?(Patterns::BlockPass)
203
+ g.push_block_arg
204
+ @arguments.pop.deconstruct(g)
205
+ end
206
+
207
+ g.cast_for_splat_block_arg
208
+ @arguments.each do |a|
209
+ if a.kind_of?(Patterns::Splat)
210
+ a.pattern.deconstruct(g)
211
+ return
212
+ else
213
+ g.shift_array
214
+ a.match(g)
215
+ end
216
+ end
217
+ g.pop
218
+ end
219
+
220
+ def local_names
221
+ @arguments.collect { |a| a.local_names }.flatten
222
+ end
223
+
224
+ def size
225
+ @arguments.size
226
+ end
227
+
228
+ def locals
229
+ local_names.size
230
+ end
231
+
232
+ def required_args
233
+ size
234
+ end
235
+
236
+ def total_args
237
+ size
238
+ end
239
+
240
+ def splat_index
241
+ @arguments.each do |a,i|
242
+ return i if a.kind_of?(Patterns::Splat)
243
+ end
244
+ nil
245
+ end
246
+ end
247
+
248
+ class BlockBody < Node
249
+ children [:expressions]
250
+ generate
251
+
252
+ def empty?
253
+ @expressions.empty?
254
+ end
255
+
256
+ def bytecode(g)
257
+ pos(g)
258
+
259
+ g.push_nil if empty?
260
+
261
+ @expressions.each_with_index do |node,idx|
262
+ g.pop unless idx == 0
263
+ node.compile(g)
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end