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/block.fy CHANGED
@@ -34,6 +34,16 @@ class Block {
34
34
  while_false: block
35
35
  }
36
36
 
37
+ def while_true: work {
38
+ {
39
+ call if_true: |val| {
40
+ work call: [val]
41
+ } else: {
42
+ break
43
+ }
44
+ } loop
45
+ }
46
+
37
47
  alias_method: 'while_do: for: 'while_true:
38
48
 
39
49
  def until_do: block {
@@ -85,6 +95,13 @@ class Block {
85
95
  }
86
96
 
87
97
  def === val {
98
+ """
99
+ @val Other object to match @self against.
100
+ @return Value of calling @self with @val.
101
+
102
+ Matches a @Block against another object by calling @self with @val.
103
+ """
104
+
88
105
  call: [val]
89
106
  }
90
- }
107
+ }
data/lib/boot.fy CHANGED
@@ -17,12 +17,15 @@ require: "object"
17
17
  require: "class"
18
18
  require: "true_class"
19
19
  require: "nil_class"
20
+ require: "false_class"
20
21
  require: "number"
21
22
  require: "enumerable"
22
23
  require: "string"
23
24
  require: "array"
24
25
  require: "tuple"
25
26
  require: "block"
27
+ require: "iteration"
28
+ require: "enumerator"
26
29
  require: "file"
27
30
  require: "directory"
28
31
  require: "fancy_spec"
@@ -36,6 +39,7 @@ require: "thread_pool"
36
39
  require: "fiber"
37
40
  require: "fiber_pool"
38
41
  require: "future"
42
+ require: "struct"
39
43
 
40
44
  # version holds fancy's version number
41
45
  require: "version"
@@ -43,4 +47,4 @@ require: "argv"
43
47
 
44
48
  require: "documentation"
45
49
 
46
- require: "package.fy"
50
+ require: "package.fy"
@@ -18,7 +18,7 @@ class Fancy AST {
18
18
  def bytecode: g {
19
19
  pos(g)
20
20
  docstring = body() body() shift_docstring
21
- docstring if_do: {
21
+ docstring if_true: {
22
22
  setdoc = MessageSend new: @line \
23
23
  message: (Identifier from: "for:append:" line: @line) \
24
24
  to: (Identifier from: "Fancy::Documentation" line: @line) \
@@ -25,10 +25,10 @@ class Fancy AST {
25
25
  }
26
26
 
27
27
  def method_name: receiver ruby_send: ruby (false) {
28
- ruby || @ruby_ident if_do: {
28
+ ruby || @ruby_ident if_true: {
29
29
  @string to_sym()
30
30
  } else: {
31
- @string =~ /:$/ . if_do: {
31
+ @string =~ /:$/ . if_true: {
32
32
  @string to_sym()
33
33
  } else: {
34
34
  ":" + @string . to_sym()
@@ -76,7 +76,7 @@ class Fancy AST {
76
76
  if: (@args last kind_of?: Identifier) then: {
77
77
  if: (@args last string =~ /^&\w/) then: {
78
78
  @block = @args pop()
79
- @block = Identifier new: (@block line) string: (@block string from: 1 to: -1)
79
+ @block = Identifier from: (@block string from: 1 to: -1) line: (@block line)
80
80
  }
81
81
  }
82
82
  }
@@ -84,7 +84,7 @@ class Fancy AST {
84
84
  if: (@args last kind_of?: Identifier) then: {
85
85
  if: (@args last string =~ /^\*\w/) then: {
86
86
  @splat = @args pop()
87
- @splat = Identifier new: (@splat line) string: (@splat string from: 1 to: -1)
87
+ @splat = Identifier from: (@splat string from: 1 to: -1) line: (@splat line)
88
88
  }
89
89
  }
90
90
  }
@@ -27,10 +27,10 @@ class Fancy AST {
27
27
  g send(@access, 0)
28
28
  g pop()
29
29
 
30
- @name to_s =~ /^initialize:(\S)+/ if_do: {
30
+ @name to_s =~ /^initialize:(\S)+/ if_true: {
31
31
  define_constructor_class_method: g
32
32
  }
33
- @name to_s =~ /^unknown_message:with_params:$/ if_do: {
33
+ @name to_s =~ /^unknown_message:with_params:$/ if_true: {
34
34
  define_method_missing: g
35
35
  }
36
36
 
@@ -1,7 +1,11 @@
1
1
  class Fancy AST {
2
2
  class TryCatch : Node {
3
3
 
4
- def initialize: @line body: @body handlers: @handlers ensure: @ensure {}
4
+ def initialize: @line body: @body handlers: @handlers ensure: @ensure {
5
+ if: (@body empty?) then: {
6
+ @body unshift_expression: $ NilLiteral new: @line
7
+ }
8
+ }
5
9
 
6
10
  def bytecode: g {
7
11
  pos(g)
data/lib/documentation.fy CHANGED
@@ -63,7 +63,7 @@ class Fancy Documentation {
63
63
  If obj has no documentation, one is created for it.
64
64
  """
65
65
  doc = for: obj
66
- doc if_do: {
66
+ if: doc then: {
67
67
  doc docs << docstring
68
68
  } else: {
69
69
  doc = for: obj is: docstring
data/lib/enumerable.fy CHANGED
@@ -19,14 +19,10 @@ class FancyEnumerable {
19
19
  calling the first @Block@ for each element in self.
20
20
  """
21
21
 
22
- count = 0
23
- size = self size
22
+ between = { between = between_block }
24
23
  each: |x| {
24
+ between call
25
25
  each_block call: [x]
26
- unless: (count == (size - 1)) do: {
27
- between_block call
28
- }
29
- count = count + 1
30
26
  }
31
27
  }
32
28
 
@@ -81,7 +77,7 @@ class FancyEnumerable {
81
77
  """
82
78
 
83
79
  each: |x| {
84
- block call: [x] . if_do: |item| {
80
+ if: (block call: [x]) then: |item| {
85
81
  return item
86
82
  }
87
83
  }
data/lib/enumerator.fy ADDED
@@ -0,0 +1,77 @@
1
+ class FancyEnumerator {
2
+ def initialize: @object {
3
+ @iterator = 'each:
4
+ rewind
5
+ }
6
+
7
+ def initialize: @object with: @iterator {
8
+ rewind
9
+ }
10
+
11
+ def next {
12
+ if: @peeked then: {
13
+ @peeked = false
14
+ @peek
15
+ } else: {
16
+ result = @fiber resume
17
+ if: (@fiber alive?) then: {
18
+ return result
19
+ } else: {
20
+ (Fancy StopIteration new: result) raise!
21
+ }
22
+ }
23
+ }
24
+
25
+ def peek {
26
+ """
27
+ Returns the next object in the FancyEnumerator, but doesn't move the
28
+ internal position forward.
29
+ When the position reaches the end, a Fancy StopIteration exception is
30
+ raised.
31
+
32
+ a = [1,2,3]
33
+ e = a to_enum
34
+ e next p #=> 1
35
+ e peek p #=> 2
36
+ e peek p #=> 2
37
+ e peek p #=> 2
38
+ e next p #=> 2
39
+ e next p #=> 3
40
+ e next p #=> raises Fancy StopIteration
41
+ """
42
+
43
+ unless: @peeked do: {
44
+ @peeked = true
45
+ @peek = @fiber resume
46
+ if: (@fiber alive?) then: {
47
+ return @peek
48
+ } else: {
49
+ (Fancy StopIteration new: result) raise!
50
+ }
51
+ }
52
+
53
+ return @peek
54
+ }
55
+
56
+ def rewind {
57
+ @peeked = false
58
+ @peek = nil
59
+
60
+ @fiber = Fiber new: {
61
+ param = |element| { yield: element }
62
+ @object send_message: @iterator with_params: [param]
63
+ }
64
+ }
65
+
66
+ def with: object each: block {
67
+ loop: {
68
+ try {
69
+ block call: [next, object]
70
+ } catch (Fancy StopIteration) => ex {
71
+ return object
72
+ }
73
+ }
74
+
75
+ return object
76
+ }
77
+ }
@@ -0,0 +1,52 @@
1
+ class FalseClass {
2
+ "FalseClass. The class of the singleton @false value."
3
+
4
+ def FalseClass new {
5
+ # always return false singleton object when trying to create a new
6
+ # FalseClass instance
7
+ false
8
+ }
9
+
10
+ def if_true: block {
11
+ "Returns @nil."
12
+ nil
13
+ }
14
+
15
+ def if_true: then_block else: else_block {
16
+ "Calls @else_block."
17
+ else_block call
18
+ }
19
+
20
+ def if_false: block {
21
+ block call: [self]
22
+ }
23
+
24
+ def if_false: then_block else: else_block {
25
+ then_block call: [self]
26
+ }
27
+
28
+ def false? {
29
+ "Returns @true."
30
+ true
31
+ }
32
+
33
+ def to_s {
34
+ "Returns @false as a @String@."
35
+ "false"
36
+ }
37
+
38
+ def to_a {
39
+ "Returns an empty @Array@."
40
+ []
41
+ }
42
+
43
+ def not {
44
+ """
45
+ @return @true
46
+
47
+ Boolean negation of @false => @true.
48
+ """
49
+
50
+ true
51
+ }
52
+ }
data/lib/fancy_spec.fy CHANGED
@@ -29,7 +29,7 @@ class FancySpec {
29
29
  def it: spec_info_string for: method_name when: spec_block {
30
30
  test = SpecTest new: spec_info_string block: spec_block
31
31
  # try {
32
- # @test_obj method: method_name . if_do: |method| {
32
+ # @test_obj method: method_name . if_true: |method| {
33
33
  # method tests << test
34
34
  # }
35
35
  # } catch MethodNotFoundError => e {
@@ -60,11 +60,11 @@ class FancySpec {
60
60
  @@failed_negative = []
61
61
 
62
62
  def SpecTest failed_test: actual_and_expected {
63
- @@failed_positive << actual_and_expected
63
+ @@failed_positive << [actual_and_expected, caller(6) at: 0]
64
64
  }
65
65
 
66
66
  def SpecTest failed_negative_test: value {
67
- @@failed_negative << value
67
+ @@failed_negative << [value, caller(6) at: 0]
68
68
  }
69
69
 
70
70
  def initialize: @info_str block: @block {
@@ -101,17 +101,24 @@ class FancySpec {
101
101
 
102
102
  def print_failed_positive {
103
103
  " [" ++ (@@failed_positive size) ++ " unexpected values]" println
104
- "Got: " println
105
- @@failed_positive each: |f| {
106
- " " ++ (f first inspect) ++ " instead of: " ++ (f second inspect) println
107
- }
104
+ print_failed_common: @@failed_positive
108
105
  }
109
106
 
110
107
  def print_failed_negative {
111
108
  " [" ++ (@@failed_negative size) ++ " unexpected values]" println
112
109
  "Should not have gotten the following values: " println
113
- @@failed_negative each: |f| {
114
- " " ++ (f inspect) println
110
+ print_failed_common: @@failed_negative
111
+ }
112
+
113
+ def print_failed_common: failures {
114
+ failures each: |f| {
115
+ actual, expected = f first
116
+ location = f second gsub(/:(\d+):in `[^']+'/, " +\1")
117
+ location = location split: "/" . from: -2 to: -1 . join: "/"
118
+
119
+ location println
120
+ " Expected: #{expected inspect}" println
121
+ " Received: #{actual inspect}" println
115
122
  }
116
123
  }
117
124
  }
@@ -132,7 +139,17 @@ class FancySpec {
132
139
 
133
140
  def != expected_value {
134
141
  unless: (@actual_value != expected_value) do: {
135
- SpecTest failed_negative_test: @actual_value
142
+ SpecTest failed_negative_test: [@actual_value, expected_value]
143
+ }
144
+ }
145
+
146
+ def raise: exception_class {
147
+ try {
148
+ @actual_value call
149
+ } catch exception_class {
150
+ # ok
151
+ } catch Exception => e {
152
+ SpecTest failed_test: [e class, exception_class]
136
153
  }
137
154
  }
138
155
 
@@ -140,7 +157,7 @@ class FancySpec {
140
157
  """Forwardy any other message and parameters to the object itself
141
158
  and checks the return value."""
142
159
 
143
- unless: (@actual_value send: msg params: params) do: {
160
+ unless: (@actual_value send_message: msg with_params: params) do: {
144
161
  SpecTest failed_test: [@actual_value, params first]
145
162
  }
146
163
  }
@@ -172,11 +189,22 @@ class FancySpec {
172
189
  }
173
190
  }
174
191
 
192
+ def raise: exception_class {
193
+ try {
194
+ @actual_value call
195
+ } catch exception_class {
196
+ SpecTest failed_negative_test: [exception_class, nil]
197
+ } catch Exception => e {
198
+ true
199
+ # ok
200
+ }
201
+ }
202
+
175
203
  def unknown_message: msg with_params: params {
176
204
  """Forwardy any other message and parameters to the object itself
177
205
  and checks the return value."""
178
206
 
179
- if: (@actual_value send: msg params: params) then: {
207
+ if: (@actual_value send_message: msg with_params: params) then: {
180
208
  SpecTest failed_negative_test: @actual_value
181
209
  }
182
210
  }
data/lib/fdoc.fy CHANGED
@@ -284,8 +284,8 @@ class Fancy FDoc {
284
284
  method = method sub(/^:/, "")
285
285
  }
286
286
  sigil = ""
287
- name =~ (Regexp.new("^#")) . if_do: { sigil = "<small>#</small>" }
288
- type = n[1] include?(":") . if_do: {
287
+ name =~ (Regexp.new("^#")) . if_true: { sigil = "<small>#</small>" }
288
+ type = n[1] include?(":") . if_true: {
289
289
  if: (sigil == "") then: {
290
290
  "singleton-method-ref"
291
291
  } else: {
data/lib/file.fy CHANGED
@@ -27,7 +27,14 @@ class File {
27
27
  lines << (f readln)
28
28
  }
29
29
  }
30
- lines join: "\n"
30
+ lines join
31
+ }
32
+
33
+ def self touch: filename {
34
+ file = File expand_path(filename)
35
+ File open: file modes: ['write] with: |f| {
36
+ f write: ""
37
+ }
31
38
  }
32
39
 
33
40
  def writeln: x {
data/lib/future.fy CHANGED
@@ -20,13 +20,34 @@ class Future {
20
20
  }
21
21
 
22
22
  def when_done: block {
23
- value if_do: |v| {
24
- block call: [v]
23
+ Future new: {
24
+ block call: [value]
25
25
  }
26
26
  }
27
27
 
28
+ def && block {
29
+ when_done: block
30
+ }
31
+
28
32
  def value {
29
33
  { Thread sleep: WaitInterval } until: { @block complete? }
30
34
  @block completed_value
31
35
  }
36
+ }
37
+
38
+ class FutureCollection {
39
+ include: FancyEnumerable
40
+
41
+ def initialize: @futures {
42
+ }
43
+
44
+ def each: block {
45
+ @futures each: |f| {
46
+ f when_done: block
47
+ }
48
+ }
49
+
50
+ def await_all {
51
+ @futures each: 'value
52
+ }
32
53
  }