fancy 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -1
- data/Rakefile +8 -0
- data/bin/fyi +25 -20
- data/bin/ifancy +39 -5
- data/{extconf.rb → boot/extconf.rb} +1 -1
- data/boot/fancy_ext/block_env.rb +0 -14
- data/boot/fancy_ext/kernel.rb +6 -2
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/examples/actor.fy +37 -0
- data/examples/armstrong_numbers.fy +1 -1
- data/examples/curl_async.fy +37 -0
- data/examples/echo.fy +1 -1
- data/examples/factorial.fy +1 -1
- data/examples/future_composition.fy +20 -0
- data/examples/game_of_life.fy +2 -2
- data/examples/person.fy +4 -8
- data/examples/rbx/blocks.fy +1 -1
- data/examples/return.fy +1 -1
- data/examples/struct.fy +9 -0
- data/lib/argv.fy +2 -2
- data/lib/array.fy +157 -0
- data/lib/block.fy +18 -1
- data/lib/boot.fy +5 -1
- data/lib/compiler/ast/class_def.fy +1 -1
- data/lib/compiler/ast/identifier.fy +2 -2
- data/lib/compiler/ast/message_send.fy +2 -2
- data/lib/compiler/ast/method_def.fy +2 -2
- data/lib/compiler/ast/try_catch.fy +5 -1
- data/lib/documentation.fy +1 -1
- data/lib/enumerable.fy +3 -7
- data/lib/enumerator.fy +77 -0
- data/lib/false_class.fy +52 -0
- data/lib/fancy_spec.fy +40 -12
- data/lib/fdoc.fy +2 -2
- data/lib/file.fy +8 -1
- data/lib/future.fy +23 -2
- data/lib/iteration.fy +60 -0
- data/lib/main.fy +4 -4
- data/lib/nil_class.fy +14 -22
- data/lib/number.fy +51 -0
- data/lib/object.fy +126 -43
- data/lib/package/installer.fy +1 -1
- data/lib/parser/ext/lexer.lex +6 -1
- data/lib/parser/ext/parser.y +18 -0
- data/lib/parser/methods.fy +20 -2
- data/lib/proxy.fy +20 -3
- data/lib/rbx.fy +0 -1
- data/lib/rbx/array.fy +4 -138
- data/lib/rbx/block.fy +25 -1
- data/lib/rbx/class.fy +21 -0
- data/lib/rbx/exception.fy +1 -0
- data/lib/rbx/fiber.fy +1 -0
- data/lib/rbx/file.fy +8 -0
- data/lib/rbx/integer.fy +0 -8
- data/lib/rbx/method.fy +34 -7
- data/lib/rbx/no_method_error.fy +8 -1
- data/lib/rbx/object.fy +3 -32
- data/lib/rbx/range.fy +13 -1
- data/lib/rbx/regexp.fy +3 -0
- data/lib/rbx/string.fy +6 -1
- data/lib/rbx/system.fy +20 -2
- data/lib/set.fy +2 -2
- data/lib/string.fy +1 -1
- data/lib/struct.fy +15 -12
- data/lib/symbol.fy +2 -2
- data/lib/true_class.fy +16 -20
- data/lib/version.fy +1 -1
- data/tests/argv.fy +1 -0
- data/tests/array.fy +33 -2
- data/tests/block.fy +44 -0
- data/tests/class.fy +102 -88
- data/tests/control_flow.fy +131 -8
- data/tests/enumerator.fy +85 -0
- data/tests/exception.fy +13 -13
- data/tests/file.fy +4 -13
- data/tests/future.fy +26 -0
- data/tests/method.fy +83 -72
- data/tests/nil_class.fy +20 -13
- data/tests/number.fy +16 -9
- data/tests/object.fy +39 -20
- data/tests/string.fy +7 -0
- data/tests/true_class.fy +4 -4
- data/tools/fancy-mode.el +1 -1
- metadata +15 -20
- data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/Makefile +0 -162
- data/boot/rbx-compiler/parser/lexer.c +0 -2316
- data/boot/rbx-compiler/parser/lexer.h +0 -315
- data/boot/rbx-compiler/parser/parser.c +0 -3105
- data/boot/rbx-compiler/parser/parser.h +0 -114
- data/lib/lazy_array.fy +0 -23
- data/lib/parser/ext/Makefile +0 -162
- data/lib/parser/ext/fancy_parser.bundle +0 -0
- data/lib/parser/ext/lexer.c +0 -2360
- data/lib/parser/ext/lexer.h +0 -315
- data/lib/parser/ext/parser.c +0 -3382
- data/lib/parser/ext/parser.h +0 -118
- 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
|
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
|
28
|
+
ruby || @ruby_ident if_true: {
|
29
29
|
@string to_sym()
|
30
30
|
} else: {
|
31
|
-
@string =~ /:$/ .
|
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
|
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
|
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)+/
|
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:$/
|
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
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
|
-
|
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]
|
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
|
+
}
|
data/lib/false_class.fy
ADDED
@@ -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 .
|
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
|
-
|
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
|
114
|
-
|
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
|
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
|
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("^#")) .
|
288
|
-
type = n[1] include?(":") .
|
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
|
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
|
-
|
24
|
-
block call: [
|
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
|
}
|