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.
Files changed (113) hide show
  1. data/{README → README.md} +33 -50
  2. data/Rakefile +6 -1
  3. data/bin/fyi +13 -10
  4. data/boot/fancy_ext.rb +1 -0
  5. data/boot/fancy_ext/block_env.rb +6 -2
  6. data/boot/fancy_ext/console.rb +4 -0
  7. data/boot/fancy_ext/object.rb +6 -0
  8. data/boot/rbx-compiler/compiler/ast/identifier.rb +5 -1
  9. data/boot/rbx-compiler/compiler/ast/match.rb +4 -5
  10. data/boot/rbx-compiler/compiler/ast/super.rb +1 -0
  11. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  12. data/boot/rbx-compiler/parser/lexer.c +2316 -0
  13. data/boot/rbx-compiler/parser/lexer.h +315 -0
  14. data/boot/rbx-compiler/parser/parser.c +3105 -0
  15. data/boot/rbx-compiler/parser/parser.h +114 -0
  16. data/boot/rbx-compiler/parser/parser.rb +2 -2
  17. data/boot/rbx-compiler/parser/parser.y +3 -3
  18. data/doc/api/fancy.jsonp +1 -1
  19. data/doc/features.md +14 -3
  20. data/examples/async_send.fy +11 -0
  21. data/examples/fibonacci.fy +1 -1
  22. data/examples/future.fy +30 -0
  23. data/examples/futures.fy +14 -0
  24. data/examples/game_of_life.fy +1 -1
  25. data/examples/matchers.fy +1 -1
  26. data/examples/pattern_matching.fy +3 -3
  27. data/examples/stupid_quicksort.fy +1 -1
  28. data/examples/threads.fy +1 -1
  29. data/extconf.rb +7 -0
  30. data/lib/array.fy +25 -5
  31. data/lib/block.fy +20 -18
  32. data/lib/boot.fy +7 -2
  33. data/lib/class.fy +33 -2
  34. data/lib/compiler/ast.fy +2 -0
  35. data/lib/compiler/ast/assign.fy +5 -5
  36. data/lib/compiler/ast/async_send.fy +25 -0
  37. data/lib/compiler/ast/block.fy +3 -3
  38. data/lib/compiler/ast/future_send.fy +20 -0
  39. data/lib/compiler/ast/identifier.fy +13 -7
  40. data/lib/compiler/ast/match.fy +32 -22
  41. data/lib/compiler/ast/message_send.fy +4 -4
  42. data/lib/compiler/ast/method_def.fy +1 -1
  43. data/lib/compiler/ast/script.fy +2 -2
  44. data/lib/compiler/ast/super.fy +1 -0
  45. data/lib/compiler/compiler.fy +2 -0
  46. data/lib/documentation.fy +4 -4
  47. data/lib/enumerable.fy +14 -7
  48. data/lib/fancy_spec.fy +2 -2
  49. data/lib/fdoc.fy +7 -7
  50. data/lib/fiber.fy +11 -0
  51. data/lib/fiber_pool.fy +78 -0
  52. data/lib/file.fy +1 -1
  53. data/lib/future.fy +32 -0
  54. data/lib/hash.fy +5 -5
  55. data/lib/lazy_array.fy +23 -0
  56. data/lib/main.fy +35 -25
  57. data/lib/method.fy +1 -1
  58. data/lib/nil_class.fy +4 -0
  59. data/lib/object.fy +59 -7
  60. data/lib/package.fy +11 -2
  61. data/lib/package/installer.fy +50 -20
  62. data/lib/package/list.fy +34 -0
  63. data/lib/package/specification.fy +19 -1
  64. data/lib/parser/ext/Makefile +162 -0
  65. data/lib/parser/ext/lexer.c +2360 -0
  66. data/lib/parser/ext/lexer.h +315 -0
  67. data/lib/parser/ext/lexer.lex +4 -0
  68. data/lib/parser/ext/parser.c +3382 -0
  69. data/lib/parser/ext/parser.h +118 -0
  70. data/lib/parser/ext/parser.y +43 -3
  71. data/lib/parser/methods.fy +34 -7
  72. data/lib/parser/parse_error.fy +10 -0
  73. data/lib/proxy.fy +16 -0
  74. data/lib/rbx.fy +3 -0
  75. data/lib/rbx/array.fy +78 -40
  76. data/lib/rbx/block.fy +35 -1
  77. data/lib/rbx/class.fy +5 -3
  78. data/lib/rbx/code_loader.fy +6 -6
  79. data/lib/rbx/console.fy +1 -1
  80. data/lib/rbx/date.fy +12 -0
  81. data/lib/rbx/documentation.fy +5 -5
  82. data/lib/rbx/exception.fy +1 -1
  83. data/lib/rbx/fiber.fy +4 -8
  84. data/lib/rbx/file.fy +4 -3
  85. data/lib/rbx/fixnum.fy +1 -0
  86. data/lib/rbx/float.fy +1 -0
  87. data/lib/rbx/hash.fy +3 -2
  88. data/lib/rbx/io.fy +5 -5
  89. data/lib/rbx/match_data.fy +10 -0
  90. data/lib/rbx/method.fy +4 -4
  91. data/lib/rbx/no_method_error.fy +1 -1
  92. data/lib/rbx/object.fy +8 -15
  93. data/lib/rbx/regexp.fy +4 -0
  94. data/lib/rbx/string.fy +39 -1
  95. data/lib/rbx/symbol.fy +1 -1
  96. data/lib/rbx/system.fy +0 -6
  97. data/lib/rbx/thread.fy +5 -0
  98. data/lib/rbx/time.fy +14 -0
  99. data/lib/rbx/tuple.fy +1 -0
  100. data/lib/set.fy +1 -1
  101. data/lib/stack.fy +1 -1
  102. data/lib/string.fy +2 -2
  103. data/lib/thread_pool.fy +101 -0
  104. data/lib/tuple.fy +37 -6
  105. data/ruby_lib/fancy.rb +46 -0
  106. data/tests/block.fy +39 -0
  107. data/tests/class.fy +40 -1
  108. data/tests/file.fy +2 -2
  109. data/tests/hash.fy +7 -7
  110. data/tests/nil_class.fy +2 -2
  111. data/tests/object.fy +10 -2
  112. data/tests/pattern_matching.fy +18 -7
  113. 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
- self print_failed_positive
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
- self print_failed_negative
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 -> self hash_to_json: obj
97
- case Array -> self array_to_json: obj
98
- case Symbol -> self symbol_to_json: obj
99
- case String -> self string_to_json: obj
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 = self generate_map
175
- json = self to_json: map
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
@@ -0,0 +1,11 @@
1
+ class Fiber {
2
+ def sleep: seconds {
3
+ @sleep_end = Time now + seconds
4
+ }
5
+
6
+ def asleep? {
7
+ if: @sleep_end then: {
8
+ Time now < @sleep_end
9
+ }
10
+ }
11
+ }
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
@@ -37,7 +37,7 @@ class File {
37
37
  """
38
38
 
39
39
  write: x
40
- self newline
40
+ newline
41
41
  }
42
42
 
43
43
  def print: x {
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
- self keys each: |key| {
19
+ keys each: |key| {
20
20
  block call: [[key, at: key]]
21
21
  }
22
22
  } else: {
23
- self keys each: |key| {
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
- self keys each: |key| {
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
- self values each: |val| {
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
- self to_a to_s
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 loads up all the necessary auto-load files by loading lib/boot.fy
4
- # and handles any given ARGV options.
5
- # Finally, if any .fy source filename is passed in via ARGV, it is
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 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
- }
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
- ["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
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
- Fancy CodeLoader load_compiled_file: file
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
@@ -17,6 +17,6 @@ class Method {
17
17
  def test: test_block {
18
18
  it = FancySpec new: self
19
19
  test_block call: [it]
20
- self tests << it
20
+ tests << it
21
21
  }
22
22
  }
data/lib/nil_class.fy CHANGED
@@ -53,4 +53,8 @@ class NilClass {
53
53
  def not {
54
54
  true
55
55
  }
56
+
57
+ def inspect {
58
+ "nil"
59
+ }
56
60
  }
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: $ self to_s
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: $ self to_s
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: (self nil?) then: {
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
- "Same as Object#or:"
99
- or: other
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
  }