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.
Files changed (94) hide show
  1. data/README.md +1 -0
  2. data/bin/fspec +3 -1
  3. data/boot/code_loader.rb +5 -1
  4. data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
  5. data/boot/fancy_ext.rb +2 -0
  6. data/boot/fancy_ext/bootstrap.rb +6 -0
  7. data/boot/fancy_ext/symbol.rb +9 -0
  8. data/boot/fancy_ext/thread.rb +22 -1
  9. data/boot/load.rb +1 -0
  10. data/boot/rbx-compiler/parser/Makefile +156 -0
  11. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  12. data/boot/rbx-compiler/parser/lexer.c +2310 -0
  13. data/boot/rbx-compiler/parser/lexer.h +315 -0
  14. data/boot/rbx-compiler/parser/parser.c +2946 -0
  15. data/boot/rbx-compiler/parser/parser.h +151 -0
  16. data/doc/api/fancy.jsonp +1 -1
  17. data/doc/features.md +8 -0
  18. data/examples/actors.fy +5 -9
  19. data/examples/actors_primitive.fy +4 -3
  20. data/examples/actors_ring.fy +15 -14
  21. data/examples/dynamic.fy +8 -0
  22. data/examples/dynamic_output.fy +15 -0
  23. data/examples/parsing.fy +1 -0
  24. data/examples/person.fy +1 -2
  25. data/lib/array.fy +49 -11
  26. data/lib/block.fy +18 -24
  27. data/lib/boot.fy +1 -1
  28. data/lib/class.fy +6 -6
  29. data/lib/compiler/ast.fy +0 -1
  30. data/lib/compiler/ast/assign.fy +25 -0
  31. data/lib/compiler/ast/block.fy +1 -0
  32. data/lib/compiler/ast/identifier.fy +16 -0
  33. data/lib/compiler/ast/literals.fy +4 -0
  34. data/lib/compiler/ast/message_send.fy +16 -1
  35. data/lib/enumerable.fy +45 -18
  36. data/lib/enumerator.fy +15 -15
  37. data/lib/false_class.fy +8 -0
  38. data/lib/fancy_spec.fy +20 -20
  39. data/lib/future.fy +35 -18
  40. data/lib/hash.fy +2 -2
  41. data/lib/integer.fy +1 -17
  42. data/lib/iteration.fy +36 -36
  43. data/lib/object.fy +65 -30
  44. data/lib/package.fy +2 -2
  45. data/lib/package/installer.fy +6 -0
  46. data/lib/parser/ext/Makefile +156 -0
  47. data/lib/parser/ext/fancy_parser.bundle +0 -0
  48. data/lib/parser/ext/lexer.c +2392 -0
  49. data/lib/parser/ext/lexer.h +315 -0
  50. data/lib/parser/ext/lexer.lex +0 -10
  51. data/lib/parser/ext/parser.c +3251 -0
  52. data/lib/parser/ext/parser.h +161 -0
  53. data/lib/parser/ext/parser.y +0 -22
  54. data/lib/parser/methods.fy +1 -13
  55. data/lib/range.fy +3 -3
  56. data/lib/rbx.fy +1 -0
  57. data/lib/rbx/actor.fy +4 -4
  58. data/lib/rbx/alpha.fy +6 -0
  59. data/lib/rbx/array.fy +5 -44
  60. data/lib/rbx/bignum.fy +1 -12
  61. data/lib/rbx/block.fy +25 -0
  62. data/lib/rbx/class.fy +1 -7
  63. data/lib/rbx/date.fy +1 -5
  64. data/lib/rbx/file.fy +1 -4
  65. data/lib/rbx/fixnum.fy +4 -16
  66. data/lib/rbx/float.fy +1 -10
  67. data/lib/rbx/integer.fy +14 -2
  68. data/lib/rbx/io.fy +1 -5
  69. data/lib/rbx/mutex.fy +30 -0
  70. data/lib/rbx/object.fy +5 -11
  71. data/lib/rbx/process.fy +13 -0
  72. data/lib/rbx/range.fy +1 -5
  73. data/lib/rbx/string.fy +4 -11
  74. data/lib/rbx/thread.fy +9 -0
  75. data/lib/rbx/time.fy +1 -7
  76. data/lib/stack.fy +1 -1
  77. data/lib/string.fy +9 -9
  78. data/lib/symbol.fy +12 -7
  79. data/lib/tuple.fy +18 -3
  80. data/lib/vars.fy +3 -0
  81. data/ruby_lib/fspec +2 -2
  82. data/ruby_lib/fyi +2 -2
  83. data/ruby_lib/ifancy +2 -2
  84. data/tests/array.fy +25 -1
  85. data/tests/assignment.fy +55 -0
  86. data/tests/future.fy +28 -0
  87. data/tests/set.fy +20 -0
  88. data/tests/stack.fy +46 -0
  89. data/tests/string.fy +1 -1
  90. data/tests/tuple.fy +22 -0
  91. data/tools/fancy-mode.el +1 -1
  92. metadata +26 -8
  93. data/lib/compiler/ast/goto.fy +0 -46
  94. data/lib/message.fy +0 -6
data/lib/block.fy CHANGED
@@ -16,13 +16,14 @@ class Block {
16
16
 
17
17
  def while_false: block {
18
18
  """
19
- Executes a given Block while self evals to nil
19
+ Executes a given @Block@ while self evals to @nil or @false.
20
+
20
21
  Example:
21
- i = 0
22
- { i >= 10 } while_false: {
23
- i println
24
- i = i + 1
25
- }
22
+ i = 0
23
+ { i >= 10 } while_false: {
24
+ i println
25
+ i = i + 1
26
+ }
26
27
  """
27
28
 
28
29
  { call not } while_true: block
@@ -30,26 +31,19 @@ class Block {
30
31
 
31
32
  alias_method: 'while_nil: for: 'while_false:
32
33
 
33
- def while_true: work {
34
+ def while_true: block {
34
35
  """
35
- @work @Block@ to call while @self yields @true.
36
+ @block @Block@ to call while @self yields @true.
36
37
 
37
- Calls @work while calling @self yields a @true-ish value.
38
+ Calls @block while calling @self yields a @true-ish value.
38
39
  """
39
40
 
40
41
  try {
41
- brk = { return nil }
42
- loop() {
43
- try {
44
- call if_true: work else: brk
45
- } catch Fancy NextIteration => ex {
46
- ex result
47
- }
48
- }
49
- } catch Fancy BreakIteration => ex {
50
- return ex result
51
- } catch Fancy StopIteration => ex {
52
- return ex result
42
+ while_true_impl: block
43
+ } catch Fancy BreakIteration => b {
44
+ return b result
45
+ } catch Fancy StopIteration => s {
46
+ return s result
53
47
  }
54
48
  }
55
49
 
@@ -90,7 +84,7 @@ class Block {
90
84
  Short-circuiting || (boolean OR).
91
85
  """
92
86
 
93
- if: call then: |val| {
87
+ call if_true: |val| {
94
88
  return val
95
89
  } else: other_block
96
90
  }
@@ -102,7 +96,7 @@ class Block {
102
96
  Calls @self if @obj is true-ish.
103
97
  """
104
98
 
105
- if: obj then: self
99
+ obj if_true: self
106
100
  }
107
101
 
108
102
  def unless: obj {
@@ -112,7 +106,7 @@ class Block {
112
106
  Opposite of Block#if:. Calls @self if @obj is false-ish.
113
107
  """
114
108
 
115
- unless: obj do: self
109
+ obj if_true: { nil } else: self
116
110
  }
117
111
 
118
112
  def === val {
data/lib/boot.fy CHANGED
@@ -30,7 +30,6 @@ require: "integer"
30
30
  require: "enumerator"
31
31
  require: "file"
32
32
  require: "directory"
33
- require: "fancy_spec"
34
33
  require: "hash"
35
34
  require: "set"
36
35
  require: "symbol"
@@ -46,6 +45,7 @@ require: "struct"
46
45
  # version holds fancy's version number
47
46
  require: "version"
48
47
  require: "argv"
48
+ require: "vars"
49
49
 
50
50
  require: "documentation"
51
51
 
data/lib/class.fy CHANGED
@@ -14,9 +14,9 @@ class Class {
14
14
 
15
15
  Defines a slot reader method with a given name.
16
16
  E.g. for a slotname @count it will define the following method:
17
- def count {
18
- get_slot: 'count
19
- }
17
+ def count {
18
+ get_slot: 'count
19
+ }
20
20
  """
21
21
 
22
22
  define_method: slotname with: {
@@ -30,9 +30,9 @@ class Class {
30
30
 
31
31
  Defines a slot writer method with a given name.
32
32
  E.g. for a slotname @count it will define the following method:
33
- def count: c {
34
- set_slot: 'count value: c
35
- }
33
+ def count: c {
34
+ set_slot: 'count value: c
35
+ }
36
36
  """
37
37
 
38
38
  define_method: (slotname to_s + ":") with: |val| {
data/lib/compiler/ast.fy CHANGED
@@ -39,5 +39,4 @@ require: "ast/range"
39
39
  require: "ast/match"
40
40
  require: "ast/try_catch"
41
41
  require: "ast/return"
42
- require: "ast/goto"
43
42
  require: "ast/string_interpolation"
@@ -92,4 +92,29 @@ class Fancy AST {
92
92
  Rubinius AST ConstantAssignment new(@line, name, value) bytecode(g)
93
93
  }
94
94
  }
95
+
96
+ class DynamicVariable {
97
+ def bytecode: g assign: value {
98
+ pos(g)
99
+ var = DynamicVariable new: @line string: @string
100
+ dva = DynamicVariableAssign new: @line varname: var value: value in: (NilLiteral new: @line)
101
+ dva bytecode: g
102
+ }
103
+ }
104
+
105
+ class DynamicVariableAssign : Node {
106
+ def initialize: @line varname: @varname value: @value in: @block {
107
+ @varname = @varname varname
108
+ }
109
+
110
+ def bytecode: g {
111
+ pos(g)
112
+
113
+ ms = MessageSend new: @line \
114
+ message: (Identifier from: "let:be:in:" line: @line) \
115
+ to: (Self new: @line) \
116
+ args: (MessageArgs new: @line args: [@varname, @value, @block])
117
+ ms bytecode: g
118
+ }
119
+ }
95
120
  }
@@ -1,5 +1,6 @@
1
1
  class Fancy AST {
2
2
  class BlockLiteral : Rubinius AST Iter {
3
+ read_slot: 'body
3
4
  def initialize: @line args: @args body: @body (NilLiteral new: line) partial: @partial (false) {
4
5
  if: (@body empty?) then: {
5
6
  @body unshift_expression: $ NilLiteral new: @line
@@ -48,6 +48,7 @@ class Fancy AST {
48
48
  case /^[A-Z]/ -> Constant
49
49
  case /^@@/ -> ClassVariable
50
50
  case /^@/ -> InstanceVariable
51
+ case /^\*/ -> DynamicVariable
51
52
  case _ -> Identifier
52
53
  }
53
54
  type new: line string: string
@@ -118,4 +119,19 @@ class Fancy AST {
118
119
  scoped bytecode(g)
119
120
  }
120
121
  }
122
+
123
+ class DynamicVariable : Identifier {
124
+ read_slot: 'varname
125
+ def initialize: @line string: @string {
126
+ @varname = SymbolLiteral new: @line value: @string
127
+ }
128
+
129
+ def bytecode: g {
130
+ thread = Identifier from: "Thread" line: @line
131
+ thread bytecode: g
132
+ g send('current, 0, false)
133
+ @varname bytecode: g
134
+ g send(':[], 1, false)
135
+ }
136
+ }
121
137
  }
@@ -89,7 +89,11 @@ class Fancy AST {
89
89
  }
90
90
 
91
91
  class SymbolLiteral : Rubinius AST SymbolLiteral {
92
+ read_slot: 'value
92
93
  def initialize: line value: value { initialize(line, value) }
94
+ def string {
95
+ value
96
+ }
93
97
  def bytecode: g {
94
98
  pos(g)
95
99
  bytecode(g)
@@ -2,6 +2,16 @@ class Fancy AST {
2
2
  class MessageSend : Node {
3
3
  read_write_slots: ['name, 'receiver, 'args]
4
4
 
5
+ # fast instructions to be used if possible
6
+ FastOps = <[
7
+ ':+ => 'meta_send_op_plus,
8
+ ':- => 'meta_send_op_minus,
9
+ ':== => 'meta_send_op_equal,
10
+ ':=== => 'meta_send_op_tequal,
11
+ ':< => 'meta_send_op_lt,
12
+ ':> => 'meta_send_op_gt
13
+ ]>
14
+
5
15
  def initialize: @line message: @name to: @receiver (Self new: @line) args: @args (MessageArgs new: @line) {
6
16
  }
7
17
 
@@ -49,7 +59,12 @@ class Fancy AST {
49
59
  if: ruby_block? then: {
50
60
  g send_with_block(sym, @args size, false)
51
61
  } else: {
52
- g send(sym, @args size, false)
62
+ # use fast instruction, if available.
63
+ if: (FastOps[sym]) then: |op| {
64
+ g __send__(op, g find_literal(sym))
65
+ } else: {
66
+ g send(sym, @args size, false)
67
+ }
53
68
  }
54
69
  }
55
70
  }
data/lib/enumerable.fy CHANGED
@@ -34,7 +34,7 @@ class FancyEnumerable {
34
34
 
35
35
  Joins a collection with a @String@ between each element, returning a new @String@.
36
36
 
37
- \"hello, world\” join: \"-\" # => \"h-e-l-l-o-,- -w-o-r-l-d\"
37
+ \"hello, world\" join: \"-\" # => \"h-e-l-l-o-,- -w-o-r-l-d\"
38
38
  """
39
39
 
40
40
  s = ""
@@ -59,13 +59,15 @@ class FancyEnumerable {
59
59
  return true
60
60
  }
61
61
  }
62
- nil
62
+ false
63
63
  }
64
64
 
65
65
  def all?: condition {
66
66
  """
67
- Similar to @FancyEnumerable#any?:@ just checking for all elements.
68
- Indicates, if all elements meet the condition.
67
+ @block Predicate @Block@ to be called for each element until it returns @false for any one of them.
68
+ @return @true if all elements in @self yield @true for @block, @false otherwise.
69
+
70
+ Takes condition-block and returns @true if all elements meet it.
69
71
  """
70
72
 
71
73
  each: |x| {
@@ -162,7 +164,7 @@ class FancyEnumerable {
162
164
  as long as they meet the given condition block.
163
165
 
164
166
  Example:
165
- [1,2,3,4,5] take_while: |x| { x < 4 } # => [1,2,3]
167
+ [1,2,3,4,5] take_while: |x| { x < 4 } # => [1,2,3]
166
168
  """
167
169
 
168
170
  coll = []
@@ -183,7 +185,7 @@ class FancyEnumerable {
183
185
  as long as they meet the given condition block.
184
186
 
185
187
  Example:
186
- [1,2,3,4,5] drop_while: |x| { x < 4 } # => [4,5]
188
+ [1,2,3,4,5] drop_while: |x| { x < 4 } # => [4,5]
187
189
  """
188
190
 
189
191
  coll = []
@@ -210,7 +212,7 @@ class FancyEnumerable {
210
212
  @return First @amount elements of @self in an @Array@.
211
213
 
212
214
  Example:
213
- [1,2,3,4] take: 2 # => [1,2]
215
+ [1,2,3,4] take: 2 # => [1,2]
214
216
  """
215
217
 
216
218
  i = 0
@@ -226,7 +228,7 @@ class FancyEnumerable {
226
228
  @return An @Array@ of all but the first @amount elements in @self.
227
229
 
228
230
  Example:
229
- [1,2,3,4,5] drop: 2 # => [3,4,5]
231
+ [1,2,3,4,5] drop: 2 # => [3,4,5]
230
232
  """
231
233
 
232
234
  i = 0
@@ -242,7 +244,7 @@ class FancyEnumerable {
242
244
  value and an initial value.
243
245
 
244
246
  Example:
245
- [1,2,3] reduce: |sum val| { sum + val } init_val: 0 # => 6
247
+ [1,2,3] reduce: |sum val| { sum + val } init_val: 0 # => 6
246
248
  """
247
249
 
248
250
  acc = init_val
@@ -258,7 +260,7 @@ class FancyEnumerable {
258
260
  and the reducing block as second parameter.
259
261
 
260
262
  Example:
261
- [1,2,3] inject: 0 into: |sum val| { sum + val } # => 6
263
+ [1,2,3] inject: 0 into: |sum val| { sum + val } # => 6
262
264
  """
263
265
 
264
266
  reduce: block init_val: val
@@ -271,7 +273,7 @@ class FancyEnumerable {
271
273
  Returns a new Array with all unique values (double entries are skipped).
272
274
 
273
275
  Example:
274
- [1,2,1,2,3] uniq # => [1,2,3]
276
+ [1,2,1,2,3] uniq # => [1,2,3]
275
277
  """
276
278
 
277
279
  uniq_vals = []
@@ -339,7 +341,7 @@ class FancyEnumerable {
339
341
  Returns a new @Array@ with all values removed that are @nil ( return @true on @nil? ).
340
342
 
341
343
  Example:
342
- [1,2,nil,3,nil] compact # => [1,2,3]
344
+ [1,2,nil,3,nil] compact # => [1,2,3]
343
345
  """
344
346
 
345
347
  reject: |x| { x nil? }
@@ -357,10 +359,10 @@ class FancyEnumerable {
357
359
  @selection_block defaults to @identity.
358
360
 
359
361
  Examples:
360
- [1,2,5,3,4] superior_by: '> # => 5
361
- [1,2,5,3,4] superior_by: '< # => 1
362
- [[1,2], [2,3,4], [], [1]] superior_by: '> taking: 'size # => [2,3,4]
363
- [[1,2], [2,3,4], [-1]] superior_by: '< taking: 'first # => [-1]
362
+ [1,2,5,3,4] superior_by: '> # => 5
363
+ [1,2,5,3,4] superior_by: '< # => 1
364
+ [[1,2], [2,3,4], [], [1]] superior_by: '> taking: 'size # => [2,3,4]
365
+ [[1,2], [2,3,4], [-1]] superior_by: '< taking: 'first # => [-1]
364
366
  """
365
367
 
366
368
 
@@ -430,7 +432,7 @@ class FancyEnumerable {
430
432
  @return @Array@ of @Array@s, partitioned by equal return values of calling @block with each element
431
433
 
432
434
  Example:
433
- 0 upto: 10 . partition_by: @{< 3} # => [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9, 10]]
435
+ 0 upto: 10 . partition_by: |x| { x < 3 } # => [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9, 10]]
434
436
  """
435
437
  last = block call: [first]
436
438
  coll = []
@@ -480,7 +482,7 @@ class FancyEnumerable {
480
482
  @return @Array@ of @Array@s with a max size of @size (grouped).
481
483
 
482
484
  Example usage:
483
- [1,2,3,4,5] in_groups_of: 3 # => [[1,2,3],[4,5]]
485
+ [1,2,3,4,5] in_groups_of: 3 # => [[1,2,3],[4,5]]
484
486
  """
485
487
 
486
488
  groups = []
@@ -503,4 +505,29 @@ class FancyEnumerable {
503
505
 
504
506
  groups
505
507
  }
508
+
509
+ def reverse {
510
+ """
511
+ @return @self in reverse order.
512
+
513
+ Returns @self in reverse order.
514
+ This only makes sense for collections that have an ordering.
515
+ In either case, it simply converts @self to an @Array@ and returns it in reversed order.
516
+ """
517
+
518
+ rev = self to_a
519
+ rev reverse
520
+ }
521
+
522
+ def reverse_each: block {
523
+ """
524
+ @block @Block@ to be called for each element in reverse order.
525
+ @return @self
526
+
527
+ Runs @block for each element on reversed version of self.
528
+ If @self is not a sorted collection, no guarantees about the reverse order can be given.
529
+ """
530
+
531
+ reverse each: block
532
+ }
506
533
  }
data/lib/enumerator.fy CHANGED
@@ -31,12 +31,12 @@ class FancyEnumerator {
31
31
  It will move the internal position forward (compared to e.g. #peek, which doesn't).
32
32
 
33
33
  Example:
34
- a = [1,2,3]
35
- e = a to_enum
36
- e next # => 1
37
- e next # => 2
38
- e next # => 3
39
- e next # => raises Fancy StopIteration
34
+ a = [1,2,3]
35
+ e = a to_enum
36
+ e next # => 1
37
+ e next # => 2
38
+ e next # => 3
39
+ e next # => raises Fancy StopIteration
40
40
  """
41
41
 
42
42
  if: @peeked then: {
@@ -70,15 +70,15 @@ class FancyEnumerator {
70
70
  raised.
71
71
 
72
72
  Example:
73
- a = [1,2,3]
74
- e = a to_enum
75
- e next p #=> 1
76
- e peek p #=> 2
77
- e peek p #=> 2
78
- e peek p #=> 2
79
- e next p #=> 2
80
- e next p #=> 3
81
- e next p #=> raises Fancy StopIteration
73
+ a = [1,2,3]
74
+ e = a to_enum
75
+ e next p #=> 1
76
+ e peek p #=> 2
77
+ e peek p #=> 2
78
+ e peek p #=> 2
79
+ e next p #=> 2
80
+ e next p #=> 3
81
+ e next p #=> raises Fancy StopIteration
82
82
  """
83
83
 
84
84
  unless: @peeked do: {
data/lib/false_class.fy CHANGED
@@ -27,6 +27,14 @@ class FalseClass {
27
27
  then_block call: [self]
28
28
  }
29
29
 
30
+ def if_nil: then_block {
31
+ nil
32
+ }
33
+
34
+ def if_nil: then_block else: else_block {
35
+ else_block call: [self]
36
+ }
37
+
30
38
  def false? {
31
39
  "Returns @true."
32
40
  true