fancy 0.4.0 → 0.5.0
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.
- data/README.md +1 -0
- data/bin/fspec +3 -1
- data/boot/code_loader.rb +5 -1
- data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
- data/boot/fancy_ext.rb +2 -0
- data/boot/fancy_ext/bootstrap.rb +6 -0
- data/boot/fancy_ext/symbol.rb +9 -0
- data/boot/fancy_ext/thread.rb +22 -1
- data/boot/load.rb +1 -0
- data/boot/rbx-compiler/parser/Makefile +156 -0
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/lexer.c +2310 -0
- data/boot/rbx-compiler/parser/lexer.h +315 -0
- data/boot/rbx-compiler/parser/parser.c +2946 -0
- data/boot/rbx-compiler/parser/parser.h +151 -0
- data/doc/api/fancy.jsonp +1 -1
- data/doc/features.md +8 -0
- data/examples/actors.fy +5 -9
- data/examples/actors_primitive.fy +4 -3
- data/examples/actors_ring.fy +15 -14
- data/examples/dynamic.fy +8 -0
- data/examples/dynamic_output.fy +15 -0
- data/examples/parsing.fy +1 -0
- data/examples/person.fy +1 -2
- data/lib/array.fy +49 -11
- data/lib/block.fy +18 -24
- data/lib/boot.fy +1 -1
- data/lib/class.fy +6 -6
- data/lib/compiler/ast.fy +0 -1
- data/lib/compiler/ast/assign.fy +25 -0
- data/lib/compiler/ast/block.fy +1 -0
- data/lib/compiler/ast/identifier.fy +16 -0
- data/lib/compiler/ast/literals.fy +4 -0
- data/lib/compiler/ast/message_send.fy +16 -1
- data/lib/enumerable.fy +45 -18
- data/lib/enumerator.fy +15 -15
- data/lib/false_class.fy +8 -0
- data/lib/fancy_spec.fy +20 -20
- data/lib/future.fy +35 -18
- data/lib/hash.fy +2 -2
- data/lib/integer.fy +1 -17
- data/lib/iteration.fy +36 -36
- data/lib/object.fy +65 -30
- data/lib/package.fy +2 -2
- data/lib/package/installer.fy +6 -0
- data/lib/parser/ext/Makefile +156 -0
- data/lib/parser/ext/fancy_parser.bundle +0 -0
- data/lib/parser/ext/lexer.c +2392 -0
- data/lib/parser/ext/lexer.h +315 -0
- data/lib/parser/ext/lexer.lex +0 -10
- data/lib/parser/ext/parser.c +3251 -0
- data/lib/parser/ext/parser.h +161 -0
- data/lib/parser/ext/parser.y +0 -22
- data/lib/parser/methods.fy +1 -13
- data/lib/range.fy +3 -3
- data/lib/rbx.fy +1 -0
- data/lib/rbx/actor.fy +4 -4
- data/lib/rbx/alpha.fy +6 -0
- data/lib/rbx/array.fy +5 -44
- data/lib/rbx/bignum.fy +1 -12
- data/lib/rbx/block.fy +25 -0
- data/lib/rbx/class.fy +1 -7
- data/lib/rbx/date.fy +1 -5
- data/lib/rbx/file.fy +1 -4
- data/lib/rbx/fixnum.fy +4 -16
- data/lib/rbx/float.fy +1 -10
- data/lib/rbx/integer.fy +14 -2
- data/lib/rbx/io.fy +1 -5
- data/lib/rbx/mutex.fy +30 -0
- data/lib/rbx/object.fy +5 -11
- data/lib/rbx/process.fy +13 -0
- data/lib/rbx/range.fy +1 -5
- data/lib/rbx/string.fy +4 -11
- data/lib/rbx/thread.fy +9 -0
- data/lib/rbx/time.fy +1 -7
- data/lib/stack.fy +1 -1
- data/lib/string.fy +9 -9
- data/lib/symbol.fy +12 -7
- data/lib/tuple.fy +18 -3
- data/lib/vars.fy +3 -0
- data/ruby_lib/fspec +2 -2
- data/ruby_lib/fyi +2 -2
- data/ruby_lib/ifancy +2 -2
- data/tests/array.fy +25 -1
- data/tests/assignment.fy +55 -0
- data/tests/future.fy +28 -0
- data/tests/set.fy +20 -0
- data/tests/stack.fy +46 -0
- data/tests/string.fy +1 -1
- data/tests/tuple.fy +22 -0
- data/tools/fancy-mode.el +1 -1
- metadata +26 -8
- data/lib/compiler/ast/goto.fy +0 -46
- 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
|
-
|
24
|
-
|
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
|
-
|
38
|
-
|
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
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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: [ '
|
2
|
+
read_slots: [ 'receiver, 'message, 'params ]
|
3
3
|
def initialize: @actor receiver: @receiver message: @message with_params: @params ([]) {
|
4
|
-
@
|
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
|
-
|
12
|
+
@completed_mutex synchronize: {
|
10
13
|
@completed = true
|
11
14
|
@failed = true
|
12
15
|
completed!
|
13
16
|
}
|
14
17
|
}
|
15
18
|
|
16
|
-
def completed:
|
17
|
-
|
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
|
-
@
|
25
|
-
@waiting_threads = []
|
28
|
+
@condvar broadcast
|
26
29
|
}
|
27
30
|
|
28
31
|
private: 'completed!
|
29
32
|
|
30
33
|
def completed? {
|
31
|
-
|
32
|
-
|
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
|
-
|
38
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@
|
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
|
102
|
-
|
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
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
{
|
45
|
+
'Hello println
|
46
|
+
Fancy StopIteration new raise!
|
47
|
+
'World println
|
48
|
+
} loop
|
49
|
+
'Done! println
|
50
50
|
|
51
51
|
Produces:
|
52
|
-
|
53
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
32
|
+
Console println: self
|
33
33
|
|
34
34
|
Prints @self on @STDOUT, followed by a newline.
|
35
35
|
"""
|
36
36
|
|
37
|
-
|
37
|
+
*stdout* println: to_s
|
38
38
|
}
|
39
39
|
|
40
40
|
def print {
|
41
41
|
"""
|
42
42
|
Same as:
|
43
|
-
|
43
|
+
Console print: self
|
44
44
|
|
45
45
|
Prints @self on STDOUT.
|
46
46
|
"""
|
47
47
|
|
48
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
361
|
-
|
362
|
-
|
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
|
-
|
372
|
+
`cat README`
|
374
373
|
Gets translated to the following message send:
|
375
|
-
|
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
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
577
|
+
some_complex_object do: {
|
578
|
+
method_1: arg1
|
579
|
+
method_2: arg2
|
580
|
+
method_3: arg3
|
581
|
+
}
|
582
582
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
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
|
}
|