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.
- 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
|
}
|