fancy 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
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
  }