fancy 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/README.md +1 -0
  2. data/bin/fspec +3 -1
  3. data/boot/code_loader.rb +5 -1
  4. data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
  5. data/boot/fancy_ext.rb +2 -0
  6. data/boot/fancy_ext/bootstrap.rb +6 -0
  7. data/boot/fancy_ext/symbol.rb +9 -0
  8. data/boot/fancy_ext/thread.rb +22 -1
  9. data/boot/load.rb +1 -0
  10. data/boot/rbx-compiler/parser/Makefile +156 -0
  11. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  12. data/boot/rbx-compiler/parser/lexer.c +2310 -0
  13. data/boot/rbx-compiler/parser/lexer.h +315 -0
  14. data/boot/rbx-compiler/parser/parser.c +2946 -0
  15. data/boot/rbx-compiler/parser/parser.h +151 -0
  16. data/doc/api/fancy.jsonp +1 -1
  17. data/doc/features.md +8 -0
  18. data/examples/actors.fy +5 -9
  19. data/examples/actors_primitive.fy +4 -3
  20. data/examples/actors_ring.fy +15 -14
  21. data/examples/dynamic.fy +8 -0
  22. data/examples/dynamic_output.fy +15 -0
  23. data/examples/parsing.fy +1 -0
  24. data/examples/person.fy +1 -2
  25. data/lib/array.fy +49 -11
  26. data/lib/block.fy +18 -24
  27. data/lib/boot.fy +1 -1
  28. data/lib/class.fy +6 -6
  29. data/lib/compiler/ast.fy +0 -1
  30. data/lib/compiler/ast/assign.fy +25 -0
  31. data/lib/compiler/ast/block.fy +1 -0
  32. data/lib/compiler/ast/identifier.fy +16 -0
  33. data/lib/compiler/ast/literals.fy +4 -0
  34. data/lib/compiler/ast/message_send.fy +16 -1
  35. data/lib/enumerable.fy +45 -18
  36. data/lib/enumerator.fy +15 -15
  37. data/lib/false_class.fy +8 -0
  38. data/lib/fancy_spec.fy +20 -20
  39. data/lib/future.fy +35 -18
  40. data/lib/hash.fy +2 -2
  41. data/lib/integer.fy +1 -17
  42. data/lib/iteration.fy +36 -36
  43. data/lib/object.fy +65 -30
  44. data/lib/package.fy +2 -2
  45. data/lib/package/installer.fy +6 -0
  46. data/lib/parser/ext/Makefile +156 -0
  47. data/lib/parser/ext/fancy_parser.bundle +0 -0
  48. data/lib/parser/ext/lexer.c +2392 -0
  49. data/lib/parser/ext/lexer.h +315 -0
  50. data/lib/parser/ext/lexer.lex +0 -10
  51. data/lib/parser/ext/parser.c +3251 -0
  52. data/lib/parser/ext/parser.h +161 -0
  53. data/lib/parser/ext/parser.y +0 -22
  54. data/lib/parser/methods.fy +1 -13
  55. data/lib/range.fy +3 -3
  56. data/lib/rbx.fy +1 -0
  57. data/lib/rbx/actor.fy +4 -4
  58. data/lib/rbx/alpha.fy +6 -0
  59. data/lib/rbx/array.fy +5 -44
  60. data/lib/rbx/bignum.fy +1 -12
  61. data/lib/rbx/block.fy +25 -0
  62. data/lib/rbx/class.fy +1 -7
  63. data/lib/rbx/date.fy +1 -5
  64. data/lib/rbx/file.fy +1 -4
  65. data/lib/rbx/fixnum.fy +4 -16
  66. data/lib/rbx/float.fy +1 -10
  67. data/lib/rbx/integer.fy +14 -2
  68. data/lib/rbx/io.fy +1 -5
  69. data/lib/rbx/mutex.fy +30 -0
  70. data/lib/rbx/object.fy +5 -11
  71. data/lib/rbx/process.fy +13 -0
  72. data/lib/rbx/range.fy +1 -5
  73. data/lib/rbx/string.fy +4 -11
  74. data/lib/rbx/thread.fy +9 -0
  75. data/lib/rbx/time.fy +1 -7
  76. data/lib/stack.fy +1 -1
  77. data/lib/string.fy +9 -9
  78. data/lib/symbol.fy +12 -7
  79. data/lib/tuple.fy +18 -3
  80. data/lib/vars.fy +3 -0
  81. data/ruby_lib/fspec +2 -2
  82. data/ruby_lib/fyi +2 -2
  83. data/ruby_lib/ifancy +2 -2
  84. data/tests/array.fy +25 -1
  85. data/tests/assignment.fy +55 -0
  86. data/tests/future.fy +28 -0
  87. data/tests/set.fy +20 -0
  88. data/tests/stack.fy +46 -0
  89. data/tests/string.fy +1 -1
  90. data/tests/tuple.fy +22 -0
  91. data/tools/fancy-mode.el +1 -1
  92. metadata +26 -8
  93. data/lib/compiler/ast/goto.fy +0 -46
  94. data/lib/message.fy +0 -6
data/lib/fancy_spec.fy CHANGED
@@ -20,9 +20,9 @@ class FancySpec {
20
20
  Factory method for creating FancySpec instances.
21
21
  Calls @block with the new FancySpec instance as the receiver, then runs it.
22
22
 
23
- FancySpec describe: MyTestClass with: {
24
- # test cases using it:for:when: here.
25
- }
23
+ FancySpec describe: MyTestClass with: {
24
+ # test cases using it:for:when: here.
25
+ }
26
26
  """
27
27
 
28
28
  spec = FancySpec new: test_obj
@@ -34,9 +34,9 @@ class FancySpec {
34
34
  """
35
35
  Similar to FancySpec##describe:with: but also taking an explicit @test_obj.
36
36
 
37
- FancySpec describe: \"My cool class\" for: MyCoolClass with: {
38
- # test cases using it:for:when: here.
39
- }
37
+ FancySpec describe: \"My cool class\" for: MyCoolClass with: {
38
+ # test cases using it:for:when: here.
39
+ }
40
40
  """
41
41
 
42
42
  spec = FancySpec new: description test_obj: test_obj
@@ -49,12 +49,12 @@ class FancySpec {
49
49
  @spec_info_string Info @String@ related to the test case defined in @spec_block.
50
50
  @spec_block @Block@ that holds the testcase's code (including assertions).
51
51
 
52
- Example usage:
53
- it: \"should be an empty Array\" when: {
54
- arr = [1,2,3]
55
- 3 times: { arr pop }
56
- arr empty? is == true
57
- }
52
+ Example:
53
+ it: \"should be an empty Array\" when: {
54
+ arr = [1,2,3]
55
+ 3 times: { arr pop }
56
+ arr empty? is == true
57
+ }
58
58
  """
59
59
 
60
60
  test = SpecTest new: spec_info_string block: spec_block
@@ -67,12 +67,12 @@ class FancySpec {
67
67
  @method_name Name of Method that this testcase is related to.
68
68
  @spec_block @Block@ that holds the testcase's code (including assertions).
69
69
 
70
- Example usage:
71
- it: \"should be an empty Array\" with: 'empty? when: {
72
- arr = [1,2,3]
73
- 3 times: { arr pop }
74
- arr empty? is == true
75
- }
70
+ Example:
71
+ it: \"should be an empty Array\" with: 'empty? when: {
72
+ arr = [1,2,3]
73
+ 3 times: { arr pop }
74
+ arr empty? is == true
75
+ }
76
76
  """
77
77
 
78
78
  test = SpecTest new: spec_info_string block: spec_block
@@ -175,7 +175,7 @@ class FancySpec {
175
175
  @@current
176
176
  }
177
177
 
178
- def SpecTest print_failures {
178
+ def SpecTest print_failures: start_time {
179
179
  @@failed_positive each: |test_obj failed_tests| {
180
180
  failed_tests each: |t| {
181
181
  Console newline
@@ -193,7 +193,7 @@ class FancySpec {
193
193
  }
194
194
 
195
195
  Console newline
196
- "Ran #{@@total_tests} tests (#{@@total_expectations} expectations) with #{@@failed_count} failures." println
196
+ "Ran #{@@total_tests} tests (#{@@total_expectations} expectations) with #{@@failed_count} failures in #{Time now - start_time} seconds." println
197
197
  if: (@@failed_count > 0) then: {
198
198
  System exit: 1
199
199
  } else: {
data/lib/future.fy CHANGED
@@ -1,54 +1,71 @@
1
1
  class FutureSend {
2
- read_slots: [ 'fail_reason, 'receiver, 'message, 'params ]
2
+ read_slots: [ 'receiver, 'message, 'params ]
3
3
  def initialize: @actor receiver: @receiver message: @message with_params: @params ([]) {
4
- @waiting_threads = []
4
+ @completed_mutex = Mutex new
5
+ @condvar = ConditionVariable new
6
+ @completed = false
7
+ @failed = false
5
8
  @actor ! ('future, (@message, @params), self)
6
9
  }
7
10
 
8
11
  def failed: @fail_reason {
9
- synchronized: {
12
+ @completed_mutex synchronize: {
10
13
  @completed = true
11
14
  @failed = true
12
15
  completed!
13
16
  }
14
17
  }
15
18
 
16
- def completed: @value {
17
- synchronized: {
19
+ def completed: value {
20
+ @completed_mutex synchronize: {
21
+ @value = value
18
22
  @completed = true
19
23
  completed!
20
24
  }
21
25
  }
22
26
 
23
27
  def completed! {
24
- @waiting_threads each: 'run
25
- @waiting_threads = []
28
+ @condvar broadcast
26
29
  }
27
30
 
28
31
  private: 'completed!
29
32
 
30
33
  def completed? {
31
- synchronized: {
32
- return @completed
34
+ completed = false
35
+ @completed_mutex synchronize: {
36
+ completed = @completed
33
37
  }
38
+ return completed true?
34
39
  }
35
40
 
36
41
  def failed? {
37
- synchronized: {
38
- return @failed
42
+ failed = false
43
+ @completed_mutex synchronize: {
44
+ failed = @failed
39
45
  }
46
+ return failed true?
47
+ }
48
+
49
+ def failure {
50
+ @completed_mutex synchronize: {
51
+ if: @failed then: {
52
+ return @fail_reason
53
+ } else: {
54
+ @condvar wait: @completed_mutex
55
+ }
56
+ }
57
+ return @fail_reason
40
58
  }
41
59
 
42
60
  def value {
43
- if: completed? then: {
44
- return @value
45
- } else: {
46
- synchronized: {
47
- @waiting_threads << (Thread current)
61
+ @completed_mutex synchronize: {
62
+ if: @completed then: {
63
+ return @value
64
+ } else: {
65
+ @condvar wait: @completed_mutex
48
66
  }
49
- Thread stop
50
- return @value
51
67
  }
68
+ return @value
52
69
  }
53
70
 
54
71
  def send_future: message with_params: params {
data/lib/hash.fy CHANGED
@@ -98,8 +98,8 @@ class Hash {
98
98
  @keys Collection of keys to get the values for.
99
99
  @return @Array@ of all values for the given keys.
100
100
 
101
- Example usage:
102
- <['foo => 1, 'bar => 2, 'baz => 42]> values_at: ('foo, 'baz) # => [1, 42]
101
+ Example:
102
+ <['foo => 1, 'bar => 2, 'baz => 42]> values_at: ('foo, 'baz) # => [1, 42]
103
103
  """
104
104
 
105
105
  keys map: |k| { at: k }
data/lib/integer.fy CHANGED
@@ -3,22 +3,6 @@ class Integer {
3
3
  Base class for integer values in Fancy.
4
4
  """
5
5
 
6
- def times: block {
7
- """
8
- @block @Block@ to be called with each number between 0 and @self.
9
- @return @self
10
-
11
- Calls a given @Block@ with each number between 0 and @self.
12
- """
13
-
14
- tmp = 0
15
- while: { tmp < self } do: {
16
- block call: [tmp]
17
- tmp = tmp + 1
18
- }
19
- self
20
- }
21
-
22
6
  def times: block offset: offset {
23
7
  """
24
8
  @block @Block@ to be called with each number between @offset and @self.
@@ -28,7 +12,7 @@ class Integer {
28
12
  Similar to #times: but starts at a given offset.
29
13
  """
30
14
 
31
- self times: |i| {
15
+ times: |i| {
32
16
  block call: [i + offset]
33
17
  }
34
18
  }
data/lib/iteration.fy CHANGED
@@ -5,20 +5,20 @@ class Fancy {
5
5
  It is rescued by Block#loop.
6
6
 
7
7
  Example:
8
- 10 times: |i| {
9
- i println
10
- if: (i == 3) then: {
11
- Fancy BreakIteration new raise!
12
- }
13
- }
14
- \"Done!\" println
8
+ 10 times: |i| {
9
+ i println
10
+ if: (i == 3) then: {
11
+ Fancy BreakIteration new raise!
12
+ }
13
+ }
14
+ \"Done!\" println
15
15
 
16
16
  Produces:
17
- 0
18
- 1
19
- 2
20
- 3
21
- Done!
17
+ 0
18
+ 1
19
+ 2
20
+ 3
21
+ Done!
22
22
  """
23
23
 
24
24
  read_slots: ['result]
@@ -41,16 +41,16 @@ class Fancy {
41
41
  It is rescued by Block#loop.
42
42
 
43
43
  Example:
44
- {
45
- 'Hello println
46
- Fancy StopIteration new raise!
47
- 'World println
48
- } loop
49
- 'Done! println
44
+ {
45
+ 'Hello println
46
+ Fancy StopIteration new raise!
47
+ 'World println
48
+ } loop
49
+ 'Done! println
50
50
 
51
51
  Produces:
52
- Hello
53
- Done!
52
+ Hello
53
+ Done!
54
54
  """
55
55
 
56
56
  def initialize { @result = nil }
@@ -60,23 +60,23 @@ class Fancy {
60
60
  """
61
61
  Returns the return value of the iterator.
62
62
 
63
- o = Object new
64
- def o each: block {
65
- block call: [1]
66
- block call: [2]
67
- block call: [3]
68
- 100
69
- }
63
+ o = Object new
64
+ def o each: block {
65
+ block call: [1]
66
+ block call: [2]
67
+ block call: [3]
68
+ 100
69
+ }
70
70
 
71
- e = o to_enum
72
- e next p #=> 1
73
- e next p #=> 2
74
- e next p #=> 3
75
- try {
76
- e next
77
- } catch Fancy StopIteration => ex {
78
- ex result p #=> 100
79
- }
71
+ e = o to_enum
72
+ e next p #=> 1
73
+ e next p #=> 2
74
+ e next p #=> 3
75
+ try {
76
+ e next
77
+ } catch Fancy StopIteration => ex {
78
+ ex result p #=> 100
79
+ }
80
80
  """
81
81
 
82
82
  @result
data/lib/object.fy CHANGED
@@ -29,23 +29,23 @@ class Object {
29
29
  def println {
30
30
  """
31
31
  Same as:
32
- Console println: self
32
+ Console println: self
33
33
 
34
34
  Prints @self on @STDOUT, followed by a newline.
35
35
  """
36
36
 
37
- Console println: to_s
37
+ *stdout* println: to_s
38
38
  }
39
39
 
40
40
  def print {
41
41
  """
42
42
  Same as:
43
- Console print: self
43
+ Console print: self
44
44
 
45
45
  Prints @self on STDOUT.
46
46
  """
47
47
 
48
- Console print: to_s
48
+ *stdout* print: to_s
49
49
  }
50
50
 
51
51
  def != other {
@@ -219,7 +219,7 @@ class Object {
219
219
  def if: cond then: block {
220
220
  """
221
221
  Same as:
222
- cond if_true: block
222
+ cond if_true: block
223
223
  """
224
224
 
225
225
  cond if_true: block
@@ -228,7 +228,7 @@ class Object {
228
228
  def if: cond then: then_block else: else_block {
229
229
  """
230
230
  Same as:
231
- cond if_true: then_block else: else_block
231
+ cond if_true: then_block else: else_block
232
232
  """
233
233
 
234
234
  cond if_true: then_block else: else_block
@@ -237,7 +237,7 @@ class Object {
237
237
  def while: cond_block do: body_block {
238
238
  """
239
239
  Same as:
240
- cond_block while_do: body_block
240
+ cond_block while_do: body_block
241
241
  """
242
242
 
243
243
  cond_block while_do: body_block
@@ -246,7 +246,7 @@ class Object {
246
246
  def until: cond_block do: body_block {
247
247
  """
248
248
  Same as:
249
- cond_block until_do: body_block
249
+ cond_block until_do: body_block
250
250
  """
251
251
 
252
252
  cond_block until_do: body_block
@@ -275,7 +275,7 @@ class Object {
275
275
  def unless: cond do: block {
276
276
  """
277
277
  Same as:
278
- cond if_true: { nil } else: block
278
+ cond if_true: { nil } else: block
279
279
  """
280
280
 
281
281
  cond if_true: { nil } else: block
@@ -284,7 +284,7 @@ class Object {
284
284
  def unless: cond do: block else: else_block {
285
285
  """
286
286
  Same as:
287
- cond if_true: else_block else: block
287
+ cond if_true: else_block else: block
288
288
  """
289
289
 
290
290
  cond if_true: else_block else: block
@@ -338,11 +338,11 @@ class Object {
338
338
  Returns @value after calling @block with it.
339
339
  Useful for returning some object after using it, e.g.:
340
340
 
341
- # this will return [1,2]
342
- returning: [] do: |arr| {
343
- arr << 1
344
- arr << 2
345
- }
341
+ # this will return [1,2]
342
+ returning: [] do: |arr| {
343
+ arr << 1
344
+ arr << 2
345
+ }
346
346
  """
347
347
 
348
348
  val = value
@@ -357,10 +357,9 @@ class Object {
357
357
  Returns a @RespondsToProxy@ for @self that forwards any messages
358
358
  only if @self responds to them.
359
359
 
360
- Example usage:
361
-
362
- # only send 'some_message: if object responds to it:
363
- object if_responds? some_message: some_parameter
360
+ Example:
361
+ # only send 'some_message: if object responds to it:
362
+ object if_responds? some_message: some_parameter
364
363
  """
365
364
 
366
365
  RespondsToProxy new: self
@@ -370,9 +369,9 @@ class Object {
370
369
  """
371
370
  This is the default implementation for backtick: which gets called when using the backtick syntax.
372
371
  For example:
373
- `cat README`
372
+ `cat README`
374
373
  Gets translated to the following message send:
375
- self backtick: \"cat README\"
374
+ self backtick: \"cat README\"
376
375
  Which allows for custom implementations of the backtick: method, if needed.
377
376
  This default implementation works the same way as in Ruby, Perl or Bash.
378
377
  It returns the output of running the given string on the command line as a @String@.
@@ -570,23 +569,25 @@ class Object {
570
569
  def do: block {
571
570
  """
572
571
  @block @Block@ to be called in the context of @self.
572
+ @return @self.
573
573
 
574
574
  Helper method that calls @block with @self as the receiver.
575
575
  This allows message cascading like code, e.g.:
576
576
 
577
- some_complex_object do: {
578
- method_1: arg1
579
- method_2: arg2
580
- method_3: arg3
581
- }
577
+ some_complex_object do: {
578
+ method_1: arg1
579
+ method_2: arg2
580
+ method_3: arg3
581
+ }
582
582
 
583
- # this is the same as:
584
- some_complex_object method_1: arg1
585
- some_complex_object method_2: arg2
586
- some_complex_object method_3: arg3
583
+ # this is the same as:
584
+ some_complex_object method_1: arg1
585
+ some_complex_object method_2: arg2
586
+ some_complex_object method_3: arg3
587
587
  """
588
588
 
589
589
  block call_with_receiver: self
590
+ self
590
591
  }
591
592
 
592
593
  def slots {
@@ -608,4 +609,38 @@ class Object {
608
609
 
609
610
  Thread sleep: seconds
610
611
  }
612
+
613
+ def let: var_name be: value in: block (nil) {
614
+ """
615
+ @var_name @Symbol@ that represents the name of the dynamic variable to be set.
616
+ @value Value for the variable.
617
+ @block @Block@ in which @var_name will be dynamically bound to @value.
618
+ @return Returns @value
619
+
620
+ Dynamically rebinds @var_name as dynamic variable with @value as the value within @block.
621
+
622
+ Example:
623
+ File open: \"/tmp/output.txt\" modes: ['write] with: |f| {
624
+ let: '*stdout* be: f in: {
625
+ \"hello, world!\" println # writes it to file not STDOUT
626
+ }
627
+ }
628
+ """
629
+
630
+ { return value } unless: var_name
631
+ unless: block do: {
632
+ Thread current[var_name]: value
633
+ return value
634
+ }
635
+
636
+ oldval = Thread current[var_name]
637
+ retval = nil
638
+ try {
639
+ Thread current[var_name]: value
640
+ retval = block call
641
+ } finally {
642
+ Thread current[var_name]: oldval
643
+ return retval
644
+ }
645
+ }
611
646
  }