fancy 0.3.0 → 0.3.1
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 → README.md} +33 -50
- data/Rakefile +6 -1
- data/bin/fyi +13 -10
- data/boot/fancy_ext.rb +1 -0
- data/boot/fancy_ext/block_env.rb +6 -2
- data/boot/fancy_ext/console.rb +4 -0
- data/boot/fancy_ext/object.rb +6 -0
- data/boot/rbx-compiler/compiler/ast/identifier.rb +5 -1
- data/boot/rbx-compiler/compiler/ast/match.rb +4 -5
- data/boot/rbx-compiler/compiler/ast/super.rb +1 -0
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/lexer.c +2316 -0
- data/boot/rbx-compiler/parser/lexer.h +315 -0
- data/boot/rbx-compiler/parser/parser.c +3105 -0
- data/boot/rbx-compiler/parser/parser.h +114 -0
- data/boot/rbx-compiler/parser/parser.rb +2 -2
- data/boot/rbx-compiler/parser/parser.y +3 -3
- data/doc/api/fancy.jsonp +1 -1
- data/doc/features.md +14 -3
- data/examples/async_send.fy +11 -0
- data/examples/fibonacci.fy +1 -1
- data/examples/future.fy +30 -0
- data/examples/futures.fy +14 -0
- data/examples/game_of_life.fy +1 -1
- data/examples/matchers.fy +1 -1
- data/examples/pattern_matching.fy +3 -3
- data/examples/stupid_quicksort.fy +1 -1
- data/examples/threads.fy +1 -1
- data/extconf.rb +7 -0
- data/lib/array.fy +25 -5
- data/lib/block.fy +20 -18
- data/lib/boot.fy +7 -2
- data/lib/class.fy +33 -2
- data/lib/compiler/ast.fy +2 -0
- data/lib/compiler/ast/assign.fy +5 -5
- data/lib/compiler/ast/async_send.fy +25 -0
- data/lib/compiler/ast/block.fy +3 -3
- data/lib/compiler/ast/future_send.fy +20 -0
- data/lib/compiler/ast/identifier.fy +13 -7
- data/lib/compiler/ast/match.fy +32 -22
- data/lib/compiler/ast/message_send.fy +4 -4
- data/lib/compiler/ast/method_def.fy +1 -1
- data/lib/compiler/ast/script.fy +2 -2
- data/lib/compiler/ast/super.fy +1 -0
- data/lib/compiler/compiler.fy +2 -0
- data/lib/documentation.fy +4 -4
- data/lib/enumerable.fy +14 -7
- data/lib/fancy_spec.fy +2 -2
- data/lib/fdoc.fy +7 -7
- data/lib/fiber.fy +11 -0
- data/lib/fiber_pool.fy +78 -0
- data/lib/file.fy +1 -1
- data/lib/future.fy +32 -0
- data/lib/hash.fy +5 -5
- data/lib/lazy_array.fy +23 -0
- data/lib/main.fy +35 -25
- data/lib/method.fy +1 -1
- data/lib/nil_class.fy +4 -0
- data/lib/object.fy +59 -7
- data/lib/package.fy +11 -2
- data/lib/package/installer.fy +50 -20
- data/lib/package/list.fy +34 -0
- data/lib/package/specification.fy +19 -1
- data/lib/parser/ext/Makefile +162 -0
- data/lib/parser/ext/lexer.c +2360 -0
- data/lib/parser/ext/lexer.h +315 -0
- data/lib/parser/ext/lexer.lex +4 -0
- data/lib/parser/ext/parser.c +3382 -0
- data/lib/parser/ext/parser.h +118 -0
- data/lib/parser/ext/parser.y +43 -3
- data/lib/parser/methods.fy +34 -7
- data/lib/parser/parse_error.fy +10 -0
- data/lib/proxy.fy +16 -0
- data/lib/rbx.fy +3 -0
- data/lib/rbx/array.fy +78 -40
- data/lib/rbx/block.fy +35 -1
- data/lib/rbx/class.fy +5 -3
- data/lib/rbx/code_loader.fy +6 -6
- data/lib/rbx/console.fy +1 -1
- data/lib/rbx/date.fy +12 -0
- data/lib/rbx/documentation.fy +5 -5
- data/lib/rbx/exception.fy +1 -1
- data/lib/rbx/fiber.fy +4 -8
- data/lib/rbx/file.fy +4 -3
- data/lib/rbx/fixnum.fy +1 -0
- data/lib/rbx/float.fy +1 -0
- data/lib/rbx/hash.fy +3 -2
- data/lib/rbx/io.fy +5 -5
- data/lib/rbx/match_data.fy +10 -0
- data/lib/rbx/method.fy +4 -4
- data/lib/rbx/no_method_error.fy +1 -1
- data/lib/rbx/object.fy +8 -15
- data/lib/rbx/regexp.fy +4 -0
- data/lib/rbx/string.fy +39 -1
- data/lib/rbx/symbol.fy +1 -1
- data/lib/rbx/system.fy +0 -6
- data/lib/rbx/thread.fy +5 -0
- data/lib/rbx/time.fy +14 -0
- data/lib/rbx/tuple.fy +1 -0
- data/lib/set.fy +1 -1
- data/lib/stack.fy +1 -1
- data/lib/string.fy +2 -2
- data/lib/thread_pool.fy +101 -0
- data/lib/tuple.fy +37 -6
- data/ruby_lib/fancy.rb +46 -0
- data/tests/block.fy +39 -0
- data/tests/class.fy +40 -1
- data/tests/file.fy +2 -2
- data/tests/hash.fy +7 -7
- data/tests/nil_class.fy +2 -2
- data/tests/object.fy +10 -2
- data/tests/pattern_matching.fy +18 -7
- metadata +34 -7
data/lib/fancy_spec.fy
CHANGED
@@ -86,14 +86,14 @@ class FancySpec {
|
|
86
86
|
any_failure = true
|
87
87
|
Console newline
|
88
88
|
"> FAILED: " ++ test_obj ++ " " ++ @info_str print
|
89
|
-
|
89
|
+
print_failed_positive
|
90
90
|
}
|
91
91
|
|
92
92
|
if: (@@failed_negative size > 0) then: {
|
93
93
|
any_failure = true
|
94
94
|
Console newline
|
95
95
|
"> FAILED: " ++ test_obj ++ " " ++ @info_str print
|
96
|
-
|
96
|
+
print_failed_negative
|
97
97
|
}
|
98
98
|
|
99
99
|
{ "." print } unless: any_failure
|
data/lib/fdoc.fy
CHANGED
@@ -92,11 +92,11 @@ class Fancy FDoc {
|
|
92
92
|
|
93
93
|
def to_json: obj {
|
94
94
|
# Reimplement now we have pattern matching dispatch.
|
95
|
-
match obj
|
96
|
-
case Hash ->
|
97
|
-
case Array ->
|
98
|
-
case Symbol ->
|
99
|
-
case String ->
|
95
|
+
match obj {
|
96
|
+
case Hash -> hash_to_json: obj
|
97
|
+
case Array -> array_to_json: obj
|
98
|
+
case Symbol -> symbol_to_json: obj
|
99
|
+
case String -> string_to_json: obj
|
100
100
|
case Numeric -> obj
|
101
101
|
case nil -> "null"
|
102
102
|
case _ -> "Dont know how to convert " ++ (obj inspect) ++ " to JSON" raise!
|
@@ -171,8 +171,8 @@ class Fancy FDoc {
|
|
171
171
|
|
172
172
|
|
173
173
|
def write: filename call: name ("fancy.fdoc") {
|
174
|
-
map =
|
175
|
-
json =
|
174
|
+
map = generate_map
|
175
|
+
json = to_json: map
|
176
176
|
js = "(function() { " ++ name ++ "(" ++ json ++ "); })();"
|
177
177
|
File open: filename modes: ['write] with: |out| { out print: js }
|
178
178
|
}
|
data/lib/fiber.fy
ADDED
data/lib/fiber_pool.fy
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
class FiberPool {
|
2
|
+
def initialize {
|
3
|
+
@pool = []
|
4
|
+
@scheduling = false
|
5
|
+
@mutex = Mutex new()
|
6
|
+
}
|
7
|
+
|
8
|
+
def size {
|
9
|
+
@mutex synchronize() {
|
10
|
+
@pool size
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
def add: fiber {
|
15
|
+
@mutex synchronize() {
|
16
|
+
@pool << fiber
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
def remove: fiber {
|
21
|
+
@mutex synchronize() {
|
22
|
+
@pool remove: fiber
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
def scheduling? {
|
27
|
+
@scheduling
|
28
|
+
}
|
29
|
+
|
30
|
+
def pool {
|
31
|
+
@mutex synchronize() {
|
32
|
+
pool = @pool
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
def cleanup_pool {
|
37
|
+
@mutex synchronize() {
|
38
|
+
@pool select!: 'alive?
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
def schedule {
|
43
|
+
@scheduling = true
|
44
|
+
Thread new: {
|
45
|
+
loop: {
|
46
|
+
while: {pool size > 0} do: {
|
47
|
+
pool each: |f| {
|
48
|
+
unless: (f asleep?) do: {
|
49
|
+
sleep_time = f resume
|
50
|
+
{ f sleep: sleep_time } if: sleep_time
|
51
|
+
}
|
52
|
+
}
|
53
|
+
cleanup_pool
|
54
|
+
}
|
55
|
+
Thread sleep: 1
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
class Scheduler {
|
62
|
+
@@pool = FiberPool new
|
63
|
+
def Scheduler add: fiber {
|
64
|
+
@@pool add: fiber
|
65
|
+
unless: (@@pool scheduling?) do: {
|
66
|
+
schedule
|
67
|
+
}
|
68
|
+
nil
|
69
|
+
}
|
70
|
+
|
71
|
+
def Scheduler remove: fiber {
|
72
|
+
@@pool remove: fiber
|
73
|
+
}
|
74
|
+
|
75
|
+
def Scheduler schedule {
|
76
|
+
@@pool schedule
|
77
|
+
}
|
78
|
+
}
|
data/lib/file.fy
CHANGED
data/lib/future.fy
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class Future {
|
2
|
+
@@thread_pool = nil
|
3
|
+
@@pool_size = 10
|
4
|
+
WaitInterval = 0.1
|
5
|
+
|
6
|
+
def Future pool: n {
|
7
|
+
@@pool_size = match n {
|
8
|
+
case 0 -> 10
|
9
|
+
case _ -> n
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
def Future join! {
|
14
|
+
@@thread_pool join
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize: @block {
|
18
|
+
{ @@thread_pool = ThreadPool new: @@pool_size } unless: @@thread_pool
|
19
|
+
@@thread_pool execute: @block
|
20
|
+
}
|
21
|
+
|
22
|
+
def when_done: block {
|
23
|
+
value if_do: |v| {
|
24
|
+
block call: [v]
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
def value {
|
29
|
+
{ Thread sleep: WaitInterval } until: { @block complete? }
|
30
|
+
@block completed_value
|
31
|
+
}
|
32
|
+
}
|
data/lib/hash.fy
CHANGED
@@ -16,11 +16,11 @@ class Hash {
|
|
16
16
|
"Calls a given Block with each key and value."
|
17
17
|
|
18
18
|
if: (block argcount == 1) then: {
|
19
|
-
|
19
|
+
keys each: |key| {
|
20
20
|
block call: [[key, at: key]]
|
21
21
|
}
|
22
22
|
} else: {
|
23
|
-
|
23
|
+
keys each: |key| {
|
24
24
|
block call: [key, at: key]
|
25
25
|
}
|
26
26
|
}
|
@@ -29,7 +29,7 @@ class Hash {
|
|
29
29
|
def each_key: block {
|
30
30
|
"Calls a given Block with each key."
|
31
31
|
|
32
|
-
|
32
|
+
keys each: |key| {
|
33
33
|
block call: [key]
|
34
34
|
}
|
35
35
|
}
|
@@ -37,7 +37,7 @@ class Hash {
|
|
37
37
|
def each_value: block {
|
38
38
|
"Calls a given Block with each value."
|
39
39
|
|
40
|
-
|
40
|
+
values each: |val| {
|
41
41
|
block call: [val]
|
42
42
|
}
|
43
43
|
}
|
@@ -51,6 +51,6 @@ class Hash {
|
|
51
51
|
def to_s {
|
52
52
|
"Returns a string representation of a Hash."
|
53
53
|
|
54
|
-
|
54
|
+
to_a to_s
|
55
55
|
}
|
56
56
|
}
|
data/lib/lazy_array.fy
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require: "rbx/fiber"
|
2
|
+
class LazyArray {
|
3
|
+
def initialize: generator {
|
4
|
+
@generator = Fiber new: generator
|
5
|
+
}
|
6
|
+
|
7
|
+
def each: block {
|
8
|
+
while: (@generator resume) do: |val| {
|
9
|
+
block call: [val]
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
def map: block {
|
14
|
+
LazyArray new: block
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
l1 = LazyArray new: |i| { i doubled }
|
19
|
+
l2 = l1 map: |x| { x squared }
|
20
|
+
|
21
|
+
l2 each: |x| {
|
22
|
+
x inspect println
|
23
|
+
}
|
data/lib/main.fy
CHANGED
@@ -1,31 +1,32 @@
|
|
1
1
|
# main.fy
|
2
2
|
# This file gets run directly from bin/fancy.
|
3
|
-
# It
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# loaded and executed.
|
3
|
+
# It handles any given built-in ARGV options.
|
4
|
+
# If any .fy source filename is passed in via ARGV, it is loaded and
|
5
|
+
# executed, otherwise ifancy, Fancy's REPL, gets loaded.
|
7
6
|
|
8
|
-
ARGV
|
9
|
-
"
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
if: (ARGV size == 1) then: {
|
8
|
+
ARGV for_options: ["-v", "--version"] do: {
|
9
|
+
"Fancy " ++ FANCY_VERSION println
|
10
|
+
"(C) 2010, 2011 Christopher Bertels <chris@fancy-lang.org>" println
|
11
|
+
System exit
|
12
|
+
}
|
13
13
|
|
14
|
-
ARGV for_options: ["--help", "-h"] do: {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
14
|
+
ARGV for_options: ["--help", "-h"] do: {
|
15
|
+
["Usage: fancy [option] [programfile] [arguments]",
|
16
|
+
" --help Print this output",
|
17
|
+
" -h Print this output",
|
18
|
+
" --version Print Fancy's version number",
|
19
|
+
" -v Print Fancy's version number",
|
20
|
+
" -I directory Add directory to Fancy's LOAD_PATH",
|
21
|
+
" -e 'command' One line of Fancy code that gets evaluated immediately",
|
22
|
+
" -c [filenames] Compile given files to Rubinius bytecode",
|
23
|
+
" -cv [filenames] Compile given files to Rubinius bytecode verbosely (outputting the generated bytecode).",
|
24
|
+
"",
|
25
|
+
"Fancy package management:",
|
26
|
+
" install [packagename] Install a Fancy package with a given name to $FANCYPACK_DIR",
|
27
|
+
" uninstall [packagename] Uninstall a Fancy package with a given name from $FANCYPACK_DIR"] println
|
28
|
+
System exit # quit when running --help
|
29
|
+
}
|
29
30
|
}
|
30
31
|
|
31
32
|
ARGV for_option: "-I" do: |path| {
|
@@ -67,12 +68,21 @@ ARGV for_option: "uninstall" do: |package_name| {
|
|
67
68
|
System exit
|
68
69
|
}
|
69
70
|
|
71
|
+
ARGV for_option: "list-packages" do: {
|
72
|
+
Fancy Package list_packages
|
73
|
+
System exit
|
74
|
+
}
|
75
|
+
|
70
76
|
# push package install dir to load_path
|
71
77
|
Fancy Package add_to_loadpath
|
72
78
|
|
73
79
|
# Load a source file, if any given:
|
74
80
|
ARGV first if_do: |file| {
|
75
|
-
|
81
|
+
try {
|
82
|
+
Fancy CodeLoader load_compiled_file: file
|
83
|
+
} catch Fancy Parser ParseError => e {
|
84
|
+
e message println
|
85
|
+
}
|
76
86
|
}
|
77
87
|
|
78
88
|
ARGV empty? if_do: {
|
data/lib/method.fy
CHANGED
data/lib/nil_class.fy
CHANGED
data/lib/object.fy
CHANGED
@@ -4,6 +4,17 @@ class Object {
|
|
4
4
|
All classes inherit from Object.
|
5
5
|
"""
|
6
6
|
|
7
|
+
def ++ other {
|
8
|
+
"""
|
9
|
+
@other Other object to concatenate its @String value with.
|
10
|
+
@return @String concatenation of @String values of @self and @other.
|
11
|
+
|
12
|
+
Returns the @String concatenation of @self and @other.
|
13
|
+
Calls to_s on @self and @other and concatenates the results to a new @String.
|
14
|
+
"""
|
15
|
+
to_s + (other to_s)
|
16
|
+
}
|
17
|
+
|
7
18
|
def loop: block {
|
8
19
|
"Infinitely calls the block (loops)."
|
9
20
|
{ true } while_true: {
|
@@ -13,12 +24,12 @@ class Object {
|
|
13
24
|
|
14
25
|
def println {
|
15
26
|
"Same as Console println: self. Prints the object on STDOUT, followed by a newline."
|
16
|
-
Console println:
|
27
|
+
Console println: to_s
|
17
28
|
}
|
18
29
|
|
19
30
|
def print {
|
20
31
|
"Same as Console print: self. Prints the object on STDOUT."
|
21
|
-
Console print:
|
32
|
+
Console print: to_s
|
22
33
|
}
|
23
34
|
|
24
35
|
def != other {
|
@@ -54,7 +65,7 @@ class Object {
|
|
54
65
|
def if_do: block {
|
55
66
|
"If the object is non-nil, it calls the given block with itself as argument."
|
56
67
|
|
57
|
-
match self
|
68
|
+
match self {
|
58
69
|
case nil -> nil
|
59
70
|
case false -> nil
|
60
71
|
case _ -> block call: [self]
|
@@ -65,7 +76,7 @@ class Object {
|
|
65
76
|
"""If the object is non-nil, it calls the given then_block with itself as argument.
|
66
77
|
Otherwise it calls the given else_block."""
|
67
78
|
|
68
|
-
match self
|
79
|
+
match self {
|
69
80
|
case nil -> else_block call: [self]
|
70
81
|
case false -> else_block call: [self]
|
71
82
|
case _ -> then_block call: [self]
|
@@ -75,7 +86,7 @@ class Object {
|
|
75
86
|
def or_take: other {
|
76
87
|
"Returns self if it's non-nil, otherwise returns the given object."
|
77
88
|
|
78
|
-
if:
|
89
|
+
if: nil? then: {
|
79
90
|
other
|
80
91
|
} else: {
|
81
92
|
self
|
@@ -95,8 +106,12 @@ class Object {
|
|
95
106
|
}
|
96
107
|
|
97
108
|
def || other {
|
98
|
-
"
|
99
|
-
|
109
|
+
"Returns @ self if self is true-ish, otherwise returns @other"
|
110
|
+
self if_do: {
|
111
|
+
return self
|
112
|
+
} else: {
|
113
|
+
return other
|
114
|
+
}
|
100
115
|
}
|
101
116
|
|
102
117
|
def && other {
|
@@ -167,4 +182,41 @@ class Object {
|
|
167
182
|
"The identity method simply returns self."
|
168
183
|
self
|
169
184
|
}
|
185
|
+
|
186
|
+
def returning: value do: block {
|
187
|
+
"""
|
188
|
+
@value Value that gets returned at the end.
|
189
|
+
@block A @Block@ that gets called with @value before returning @value.
|
190
|
+
@return @value
|
191
|
+
|
192
|
+
Returns @value after calling @block with it.
|
193
|
+
Useful for returning some object after using it, e.g.:
|
194
|
+
|
195
|
+
# this will return [1,2]
|
196
|
+
returning: [] do: |arr| {
|
197
|
+
arr << 1
|
198
|
+
arr << 2
|
199
|
+
}
|
200
|
+
"""
|
201
|
+
|
202
|
+
val = value
|
203
|
+
block call: [val]
|
204
|
+
val
|
205
|
+
}
|
206
|
+
|
207
|
+
def ? future {
|
208
|
+
future value
|
209
|
+
}
|
210
|
+
|
211
|
+
def yield {
|
212
|
+
Fiber yield
|
213
|
+
}
|
214
|
+
|
215
|
+
def yield: values {
|
216
|
+
Fiber yield: values
|
217
|
+
}
|
218
|
+
|
219
|
+
def wait: seconds {
|
220
|
+
Fiber yield: [seconds]
|
221
|
+
}
|
170
222
|
}
|