fancy 0.3.2 → 0.3.3

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 (98) hide show
  1. data/README.md +4 -1
  2. data/Rakefile +8 -0
  3. data/bin/fyi +25 -20
  4. data/bin/ifancy +39 -5
  5. data/{extconf.rb → boot/extconf.rb} +1 -1
  6. data/boot/fancy_ext/block_env.rb +0 -14
  7. data/boot/fancy_ext/kernel.rb +6 -2
  8. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  9. data/examples/actor.fy +37 -0
  10. data/examples/armstrong_numbers.fy +1 -1
  11. data/examples/curl_async.fy +37 -0
  12. data/examples/echo.fy +1 -1
  13. data/examples/factorial.fy +1 -1
  14. data/examples/future_composition.fy +20 -0
  15. data/examples/game_of_life.fy +2 -2
  16. data/examples/person.fy +4 -8
  17. data/examples/rbx/blocks.fy +1 -1
  18. data/examples/return.fy +1 -1
  19. data/examples/struct.fy +9 -0
  20. data/lib/argv.fy +2 -2
  21. data/lib/array.fy +157 -0
  22. data/lib/block.fy +18 -1
  23. data/lib/boot.fy +5 -1
  24. data/lib/compiler/ast/class_def.fy +1 -1
  25. data/lib/compiler/ast/identifier.fy +2 -2
  26. data/lib/compiler/ast/message_send.fy +2 -2
  27. data/lib/compiler/ast/method_def.fy +2 -2
  28. data/lib/compiler/ast/try_catch.fy +5 -1
  29. data/lib/documentation.fy +1 -1
  30. data/lib/enumerable.fy +3 -7
  31. data/lib/enumerator.fy +77 -0
  32. data/lib/false_class.fy +52 -0
  33. data/lib/fancy_spec.fy +40 -12
  34. data/lib/fdoc.fy +2 -2
  35. data/lib/file.fy +8 -1
  36. data/lib/future.fy +23 -2
  37. data/lib/iteration.fy +60 -0
  38. data/lib/main.fy +4 -4
  39. data/lib/nil_class.fy +14 -22
  40. data/lib/number.fy +51 -0
  41. data/lib/object.fy +126 -43
  42. data/lib/package/installer.fy +1 -1
  43. data/lib/parser/ext/lexer.lex +6 -1
  44. data/lib/parser/ext/parser.y +18 -0
  45. data/lib/parser/methods.fy +20 -2
  46. data/lib/proxy.fy +20 -3
  47. data/lib/rbx.fy +0 -1
  48. data/lib/rbx/array.fy +4 -138
  49. data/lib/rbx/block.fy +25 -1
  50. data/lib/rbx/class.fy +21 -0
  51. data/lib/rbx/exception.fy +1 -0
  52. data/lib/rbx/fiber.fy +1 -0
  53. data/lib/rbx/file.fy +8 -0
  54. data/lib/rbx/integer.fy +0 -8
  55. data/lib/rbx/method.fy +34 -7
  56. data/lib/rbx/no_method_error.fy +8 -1
  57. data/lib/rbx/object.fy +3 -32
  58. data/lib/rbx/range.fy +13 -1
  59. data/lib/rbx/regexp.fy +3 -0
  60. data/lib/rbx/string.fy +6 -1
  61. data/lib/rbx/system.fy +20 -2
  62. data/lib/set.fy +2 -2
  63. data/lib/string.fy +1 -1
  64. data/lib/struct.fy +15 -12
  65. data/lib/symbol.fy +2 -2
  66. data/lib/true_class.fy +16 -20
  67. data/lib/version.fy +1 -1
  68. data/tests/argv.fy +1 -0
  69. data/tests/array.fy +33 -2
  70. data/tests/block.fy +44 -0
  71. data/tests/class.fy +102 -88
  72. data/tests/control_flow.fy +131 -8
  73. data/tests/enumerator.fy +85 -0
  74. data/tests/exception.fy +13 -13
  75. data/tests/file.fy +4 -13
  76. data/tests/future.fy +26 -0
  77. data/tests/method.fy +83 -72
  78. data/tests/nil_class.fy +20 -13
  79. data/tests/number.fy +16 -9
  80. data/tests/object.fy +39 -20
  81. data/tests/string.fy +7 -0
  82. data/tests/true_class.fy +4 -4
  83. data/tools/fancy-mode.el +1 -1
  84. metadata +15 -20
  85. data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
  86. data/boot/rbx-compiler/parser/Makefile +0 -162
  87. data/boot/rbx-compiler/parser/lexer.c +0 -2316
  88. data/boot/rbx-compiler/parser/lexer.h +0 -315
  89. data/boot/rbx-compiler/parser/parser.c +0 -3105
  90. data/boot/rbx-compiler/parser/parser.h +0 -114
  91. data/lib/lazy_array.fy +0 -23
  92. data/lib/parser/ext/Makefile +0 -162
  93. data/lib/parser/ext/fancy_parser.bundle +0 -0
  94. data/lib/parser/ext/lexer.c +0 -2360
  95. data/lib/parser/ext/lexer.h +0 -315
  96. data/lib/parser/ext/parser.c +0 -3382
  97. data/lib/parser/ext/parser.h +0 -118
  98. data/lib/rbx/false_class.fy +0 -58
data/lib/iteration.fy ADDED
@@ -0,0 +1,60 @@
1
+ class Fancy {
2
+ class BreakIteration : StdError {
3
+ read_slots: ['return_value]
4
+ def initialize: @return_value {}
5
+ }
6
+
7
+ class NextIteration : StdError {
8
+ read_slots: ['return_value]
9
+ def initialize: @return_value {}
10
+ }
11
+
12
+ class StopIteration : StdError {
13
+ """
14
+ Raised to stop the iteration, in particular by Enumerator#next.
15
+ It is rescued by Block#loop.
16
+
17
+ Example:
18
+ {
19
+ 'Hello println
20
+ StopIteration new raise!
21
+ 'World println
22
+ } loop
23
+ 'Done! println
24
+
25
+ Produces:
26
+
27
+ Hello
28
+ Done!
29
+ """
30
+
31
+ def initialize { @result = nil }
32
+ def initialize: @result { }
33
+
34
+ def result {
35
+ """
36
+ Returns the return value of the iterator.
37
+
38
+ o = Object new
39
+ def o each: block {
40
+ block call: 1
41
+ block call: 2
42
+ block call: 3
43
+ 100
44
+ }
45
+
46
+ e = o to_enum
47
+ e next p #=> 1
48
+ e next p #=> 2
49
+ e next p #=> 3
50
+ try {
51
+ e next
52
+ } catch Fancy StopIteration => ex {
53
+ ex result p #=> 100
54
+ }
55
+ """
56
+
57
+ @result
58
+ }
59
+ }
60
+ }
data/lib/main.fy CHANGED
@@ -39,7 +39,7 @@ ARGV for_option: "-e" do: |eval_string| {
39
39
  }
40
40
 
41
41
  ARGV for_option: "-c" do: {
42
- ARGV index: "-c" . if_do: |idx| {
42
+ ARGV index: "-c" . if_true: |idx| {
43
43
  ARGV[[idx + 1, -1]] each: |filename| {
44
44
  "Compiling " ++ filename println
45
45
  Fancy Compiler compile_file: filename to: nil line: 1 print: false
@@ -49,7 +49,7 @@ ARGV for_option: "-c" do: {
49
49
  }
50
50
 
51
51
  ARGV for_option: "-cv" do: {
52
- ARGV index: "-cv" . if_do: |idx| {
52
+ ARGV index: "-cv" . if_true: |idx| {
53
53
  ARGV[[idx + 1, -1]] each: |filename| {
54
54
  "Compiling " ++ filename println
55
55
  Fancy Compiler compile_file: filename to: nil line: 1 print: true
@@ -77,7 +77,7 @@ ARGV for_option: "list-packages" do: {
77
77
  Fancy Package add_to_loadpath
78
78
 
79
79
  # Load a source file, if any given:
80
- ARGV first if_do: |file| {
80
+ ARGV first if_true: |file| {
81
81
  try {
82
82
  Fancy CodeLoader load_compiled_file: file
83
83
  } catch Fancy Parser ParseError => e {
@@ -85,6 +85,6 @@ ARGV first if_do: |file| {
85
85
  }
86
86
  }
87
87
 
88
- ARGV empty? if_do: {
88
+ ARGV empty? if_true: {
89
89
  require: "../bin/ifancy"
90
90
  }
data/lib/nil_class.fy CHANGED
@@ -1,5 +1,5 @@
1
1
  class NilClass {
2
- "NilClass. The class of the singleton nil value."
2
+ "NilClass. The class of the singleton @nil value."
3
3
 
4
4
  def NilClass new {
5
5
  # always return nil singleton object when trying to create a new
@@ -7,54 +7,46 @@ class NilClass {
7
7
  nil
8
8
  }
9
9
 
10
- def if_true: then_block else: else_block {
11
- "Calls else_block."
12
- else_block call
13
- }
14
-
15
10
  def if_true: block {
16
- "Returns nil."
11
+ "Returns @nil."
17
12
  nil
18
13
  }
19
14
 
20
- def if_false: block {
21
- "Calls the block."
22
- block call
15
+ def if_true: then_block else: else_block {
16
+ "Calls @else_block."
17
+ else_block call
23
18
  }
24
19
 
25
20
  def if_nil: block {
26
- "Calls the block."
27
- block call
21
+ block call: [self]
28
22
  }
29
23
 
30
- def nil? {
31
- "Returns true."
32
- true
24
+ def if_nil: then_block else: else_block {
25
+ then_block call: [self]
33
26
  }
34
27
 
35
- def false? {
36
- "Returns true."
28
+ def nil? {
29
+ "Returns @true."
37
30
  true
38
31
  }
39
32
 
40
- def true? {
41
- "Returns nil."
42
- false
43
- }
44
-
45
33
  def to_s {
34
+ "Returns an empty @String@."
46
35
  ""
47
36
  }
48
37
 
49
38
  def to_a {
39
+ "Returns an empty @Array@."
50
40
  []
51
41
  }
52
42
 
53
43
  def not {
44
+ "Returns @true."
54
45
  true
55
46
  }
56
47
 
57
48
  def inspect {
49
+ "Returns @nil as a @String@."
58
50
  "nil"
59
51
  }
60
52
  }
data/lib/number.fy CHANGED
@@ -5,6 +5,14 @@ class Number {
5
5
  """
6
6
 
7
7
  def upto: num {
8
+ """
9
+ @num @Number@ to create an @Array@ up to.
10
+ @return @Array@ containing numbers from @self to @num.
11
+
12
+ Returns an Array with Numbers starting at @self and going up to @num.
13
+ Expects @num to be greater or equal to @self.
14
+ """
15
+
8
16
  i = self
9
17
  arr = []
10
18
  while: { i <= num } do: {
@@ -14,7 +22,32 @@ class Number {
14
22
  arr
15
23
  }
16
24
 
25
+ def upto: num do: block {
26
+ """
27
+ @num Maximum @Number@ to call @block with.
28
+ @block A @Block@ that should be called with each @Number@ between @self and @num.
29
+ @return @self
30
+
31
+ Calls @block with each @Number@ between @self and @num.
32
+ Expects @num to be greater or equal to @self.
33
+ """
34
+ i = self
35
+ while: { i <= num } do: {
36
+ block call: [i]
37
+ i = i + 1
38
+ }
39
+ self
40
+ }
41
+
17
42
  def downto: num {
43
+ """
44
+ @num @Number@ to create an @Array@ down to.
45
+ @return @Array@ containing numbers from @self down to @num.
46
+
47
+ Returns an Array with Numbers starting at @self and going down to @num.
48
+ Expects @num to be smaller or equal to @self.
49
+ """
50
+
18
51
  i = self
19
52
  arr = []
20
53
  while: { i >= num } do: {
@@ -24,6 +57,24 @@ class Number {
24
57
  arr
25
58
  }
26
59
 
60
+ def downto: num do: block {
61
+ """
62
+ @num Minimum @Number@ to call @block with.
63
+ @block A @Block@ that should be called with each @Number@ between @self and @num.
64
+ @return @self
65
+
66
+ Calls @block with each @Number@ between @self and @num.
67
+ Expects @num to be smaller or equal to @self.
68
+ """
69
+
70
+ i = self
71
+ while: { i >= num } do: {
72
+ block call: [i]
73
+ i = i - 1
74
+ }
75
+ self
76
+ }
77
+
27
78
  def squared {
28
79
  "Returns the square of a Number."
29
80
 
data/lib/object.fy CHANGED
@@ -17,9 +17,7 @@ class Object {
17
17
 
18
18
  def loop: block {
19
19
  "Infinitely calls the block (loops)."
20
- { true } while_true: {
21
- block call
22
- }
20
+ block loop
23
21
  }
24
22
 
25
23
  def println {
@@ -37,50 +35,49 @@ class Object {
37
35
  self == other not
38
36
  }
39
37
 
40
- def if_false: block {
41
- "Calls the block."
42
- nil
38
+ def if_true: block {
39
+ "Calls the @block if @true? returns @true"
40
+ block call: [self]
43
41
  }
44
42
 
45
- def if_nil: block {
46
- "Returns nil."
47
- nil
43
+ def if_true: then_block else: else_block {
44
+ "Calls the @then_block if @true? returns @true - otherwise @else_block is called"
45
+ then_block call: [self]
48
46
  }
49
47
 
50
- def nil? {
51
- "Returns nil."
48
+ def if_false: block {
49
+ "Calls the @block if @false? returns @true@"
52
50
  nil
53
51
  }
54
52
 
55
- def false? {
56
- "Returns nil."
57
- nil
53
+ def if_false: then_block else: else_block {
54
+ "Calls the @then_block if @false? returns @true - otherwise @else_block is called"
55
+ else_block call
58
56
  }
59
57
 
60
- def true? {
61
- "Returns nil."
58
+ def if_nil: block {
59
+ "Calls the @block if @nil? returns @true@"
62
60
  nil
63
61
  }
64
62
 
65
- def if_do: block {
66
- "If the object is non-nil, it calls the given block with itself as argument."
63
+ def if_nil: then_block else: else_block {
64
+ "Calls the @then_block if @nil? returns @true - otherwise @else_block is called"
65
+ else_block call
66
+ }
67
67
 
68
- match self {
69
- case nil -> nil
70
- case false -> nil
71
- case _ -> block call: [self]
72
- }
68
+ def nil? {
69
+ "Returns @false."
70
+ false
73
71
  }
74
72
 
75
- def if_do: then_block else: else_block {
76
- """If the object is non-nil, it calls the given then_block with itself as argument.
77
- Otherwise it calls the given else_block."""
73
+ def false? {
74
+ "Returns @false."
75
+ false
76
+ }
78
77
 
79
- match self {
80
- case nil -> else_block call: [self]
81
- case false -> else_block call: [self]
82
- case _ -> then_block call: [self]
83
- }
78
+ def true? {
79
+ "Returns @false."
80
+ false
84
81
  }
85
82
 
86
83
  def or_take: other {
@@ -105,34 +102,69 @@ class Object {
105
102
  0
106
103
  }
107
104
 
108
- def || other {
109
- "Returns @ self if self is true-ish, otherwise returns @other"
110
- self if_do: {
105
+ def to_enum {
106
+ FancyEnumerator new: self
107
+ }
108
+
109
+ def to_enum: iterator {
110
+ FancyEnumerator new: self with: iterator
111
+ }
112
+
113
+ def and: other {
114
+ """
115
+ Boolean conjunction.
116
+ Returns @other if @self and @other are true-ish, otherwise @false.
117
+ """
118
+
119
+ if_true: {
120
+ { other = other call } if: (other is_a?: Block)
121
+ return other
122
+ }
123
+ return self
124
+ }
125
+
126
+ def or: other {
127
+ """
128
+ Boolean disjunction.
129
+ Returns true if either @self or other is true, otherwise nil.
130
+ """
131
+ if_true: {
111
132
  return self
112
133
  } else: {
134
+ { other = other call } if: (other is_a?: Block)
113
135
  return other
114
136
  }
115
137
  }
116
138
 
117
- def && other {
118
- "Same as Object#and:"
119
- and: other
139
+ def or: other {
140
+ """
141
+ Boolean disjunction.
142
+ Returns true if either @self or other is true, otherwise nil.
143
+ """
144
+ unless: self do: {
145
+ { other = other call } if: (other is_a?: Block)
146
+ return other
147
+ }
148
+ return self
120
149
  }
121
150
 
151
+ alias_method: ':&& for: 'and:
152
+ alias_method: ':|| for: 'or:
153
+
122
154
  def if: cond then: block {
123
155
  """
124
156
  Same as:
125
- cond if_do: block
157
+ cond if_true: block
126
158
  """
127
- cond if_do: block
159
+ cond if_true: block
128
160
  }
129
161
 
130
162
  def if: cond then: then_block else: else_block {
131
163
  """
132
164
  Same as:
133
- cond if_do: then_block else: else_block
165
+ cond if_true: then_block else: else_block
134
166
  """
135
- cond if_do: then_block else: else_block
167
+ cond if_true: then_block else: else_block
136
168
  }
137
169
 
138
170
  def while: cond_block do: body_block {
@@ -156,10 +188,10 @@ class Object {
156
188
  def unless: cond do: block {
157
189
  """
158
190
  Same as:
159
- cond if_do: { nil } else: block
191
+ cond if_true: { nil } else: block
160
192
  """
161
193
 
162
- cond if_do: { nil } else: block
194
+ cond if_true: { nil } else: block
163
195
  }
164
196
 
165
197
  def method: method_name {
@@ -204,6 +236,37 @@ class Object {
204
236
  val
205
237
  }
206
238
 
239
+ def if_responds? {
240
+ """
241
+ @return RespondsToProxy for @self
242
+
243
+ Returns a @RespondsToProxy@ for @self that forwards any messages
244
+ only if @self responds to them.
245
+
246
+ Example usage:
247
+
248
+ # only send 'some_message: if object responds to it:
249
+ object if_responds? some_message: some_parameter
250
+ """
251
+
252
+ RespondsToProxy new: self
253
+ }
254
+
255
+ def backtick: str {
256
+ """
257
+ This is the default implementation for backtick: which gets called when using the backtick syntax.
258
+ For example:
259
+ `cat README`
260
+ Gets translated to the following message send:
261
+ self backtick: \"cat README\"
262
+ Which allows for custom implementations of the backtick: method, if needed.
263
+ This default implementation works the same way as in Ruby, Perl or Bash.
264
+ It returns the output of running the given string on the command line as a @String@.
265
+ """
266
+
267
+ System pipe: str . read
268
+ }
269
+
207
270
  def ? future {
208
271
  future value
209
272
  }
@@ -219,4 +282,24 @@ class Object {
219
282
  def wait: seconds {
220
283
  Fiber yield: [seconds]
221
284
  }
285
+
286
+ def next {
287
+ "Skip to the next iteration"
288
+ Fancy NextIteration new raise!
289
+ }
290
+
291
+ def next: value {
292
+ "Return value for this iteration and skip to the next one"
293
+ (Fancy NextIteration new: value) raise!
294
+ }
295
+
296
+ def break {
297
+ "Stop iterating"
298
+ Fancy BreakIteration new raise!
299
+ }
300
+
301
+ def break: value {
302
+ "Return value from iteration"
303
+ (Fancy BreakIteration new: value) raise!
304
+ }
222
305
  }