fancy 0.5.0 → 0.6.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 (111) hide show
  1. data/AUTHORS +2 -0
  2. data/README.md +6 -1
  3. data/bin/fancy +6 -0
  4. data/bin/ifancy +44 -3
  5. data/boot/fancy_ext/module.rb +4 -0
  6. data/boot/fancy_ext/object.rb +4 -0
  7. data/boot/rbx-compiler/compiler/ast/block.rb +29 -1
  8. data/boot/rbx-compiler/compiler/ast/identifier.rb +6 -0
  9. data/boot/rbx-compiler/compiler/ast/message_send.rb +1 -0
  10. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  11. data/boot/rbx-compiler/parser/lexer.lex +2 -0
  12. data/boot/rbx-compiler/parser/parser.rb +6 -0
  13. data/boot/rbx-compiler/parser/parser.y +14 -1
  14. data/doc/api/fancy.jsonp +1 -1
  15. data/doc/features.md +24 -0
  16. data/examples/99bottles.fy +5 -0
  17. data/examples/conditions_exceptions.fy +9 -0
  18. data/examples/conditions_parsing.fy +68 -0
  19. data/examples/greeter.fy +9 -0
  20. data/examples/html_generator.fy +59 -29
  21. data/examples/webserver/webserver.fy +8 -11
  22. data/lib/argv.fy +6 -0
  23. data/lib/array.fy +17 -35
  24. data/lib/block.fy +82 -1
  25. data/lib/boot.fy +4 -2
  26. data/lib/compiler.fy +2 -2
  27. data/lib/compiler/ast/block.fy +24 -20
  28. data/lib/compiler/ast/message_send.fy +11 -0
  29. data/lib/contracts.fy +60 -0
  30. data/lib/dynamic_slot_object.fy +61 -0
  31. data/lib/enumerable.fy +432 -394
  32. data/lib/enumerator.fy +152 -150
  33. data/lib/fdoc.fy +4 -17
  34. data/lib/fiber.fy +4 -10
  35. data/lib/file.fy +33 -25
  36. data/lib/future.fy +59 -5
  37. data/lib/hash.fy +54 -1
  38. data/lib/html.fy +107 -0
  39. data/lib/kvo.fy +173 -0
  40. data/lib/main.fy +6 -2
  41. data/lib/message_sink.fy +19 -0
  42. data/lib/number.fy +48 -0
  43. data/lib/object.fy +65 -13
  44. data/lib/package.fy +12 -2
  45. data/lib/package/dependency.fy +13 -0
  46. data/lib/package/dependency_installer.fy +27 -0
  47. data/lib/package/installer.fy +4 -10
  48. data/lib/package/uninstaller.fy +1 -3
  49. data/lib/parser/ext/lexer.lex +8 -3
  50. data/lib/parser/ext/parser.y +4 -1
  51. data/lib/parser/methods.fy +7 -3
  52. data/lib/range.fy +1 -1
  53. data/lib/rbx.fy +2 -1
  54. data/lib/rbx/array.fy +28 -12
  55. data/lib/rbx/bignum.fy +1 -1
  56. data/lib/rbx/block.fy +27 -0
  57. data/lib/rbx/console.fy +6 -6
  58. data/lib/rbx/date.fy +6 -1
  59. data/lib/rbx/documentation.fy +8 -3
  60. data/lib/rbx/exception.fy +5 -0
  61. data/lib/rbx/file.fy +40 -7
  62. data/lib/rbx/fixnum.fy +12 -1
  63. data/lib/rbx/method.fy +9 -2
  64. data/lib/rbx/module.fy +24 -0
  65. data/lib/rbx/regexp.fy +8 -0
  66. data/lib/rbx/string.fy +23 -7
  67. data/lib/rbx/tcp_server.fy +4 -2
  68. data/lib/rbx/tcp_socket.fy +14 -0
  69. data/lib/remote_object.fy +59 -0
  70. data/lib/set.fy +15 -4
  71. data/lib/string.fy +38 -5
  72. data/lib/stringio.fy +1 -0
  73. data/lib/symbol.fy +4 -0
  74. data/lib/system.fy +22 -0
  75. data/lib/thread_pool.fy +2 -2
  76. data/lib/tuple.fy +18 -1
  77. data/lib/vars.fy +17 -0
  78. data/lib/version.fy +1 -1
  79. data/ruby_lib/fancy +6 -0
  80. data/tests/array.fy +30 -0
  81. data/tests/block.fy +106 -0
  82. data/tests/class.fy +19 -0
  83. data/tests/enumerable.fy +1 -1
  84. data/tests/enumerator.fy +5 -5
  85. data/tests/file.fy +28 -0
  86. data/tests/fixnum.fy +0 -50
  87. data/tests/future.fy +9 -24
  88. data/tests/hash.fy +35 -0
  89. data/tests/html.fy +33 -0
  90. data/tests/kvo.fy +101 -0
  91. data/tests/number.fy +75 -0
  92. data/tests/object.fy +50 -3
  93. data/tests/string.fy +19 -10
  94. data/tests/symbol.fy +5 -0
  95. data/tests/tuple.fy +7 -0
  96. data/tools/fancy-mode.el +5 -1
  97. metadata +22 -21
  98. data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
  99. data/boot/rbx-compiler/parser/Makefile +0 -156
  100. data/boot/rbx-compiler/parser/lexer.c +0 -2310
  101. data/boot/rbx-compiler/parser/lexer.h +0 -315
  102. data/boot/rbx-compiler/parser/parser.c +0 -2946
  103. data/boot/rbx-compiler/parser/parser.h +0 -151
  104. data/lib/fiber_pool.fy +0 -78
  105. data/lib/method.fy +0 -6
  106. data/lib/parser/ext/Makefile +0 -156
  107. data/lib/parser/ext/fancy_parser.bundle +0 -0
  108. data/lib/parser/ext/lexer.c +0 -2392
  109. data/lib/parser/ext/lexer.h +0 -315
  110. data/lib/parser/ext/parser.c +0 -3251
  111. data/lib/parser/ext/parser.h +0 -161
@@ -7,7 +7,7 @@
7
7
  if: (ARGV size == 1) then: {
8
8
  ARGV for_options: ["-v", "--version"] do: {
9
9
  "Fancy " ++ FANCY_VERSION println
10
- "(C) 2010, 2011 Christopher Bertels <chris@fancy-lang.org>" println
10
+ "(C) 2010, 2011, 2012 Christopher Bertels <chris@fancy-lang.org>" println
11
11
  System exit
12
12
  }
13
13
 
@@ -24,6 +24,7 @@ if: (ARGV size == 1) then: {
24
24
  "",
25
25
  "Fancy package management:",
26
26
  " install [packagename] Install a Fancy package with a given name to $FANCYPACK_DIR",
27
+ " install --deps Install dependencies specified in .fancypack file (expected in current directory).",
27
28
  " uninstall [packagename] Uninstall a Fancy package with a given name from $FANCYPACK_DIR"] println
28
29
  System exit # quit when running --help
29
30
  }
@@ -59,7 +60,10 @@ ARGV for_option: "-cv" do: {
59
60
  }
60
61
 
61
62
  ARGV for_option: "install" do: |package_name| {
62
- Fancy Package install: package_name
63
+ match package_name {
64
+ case "--deps" -> Fancy Package install_dependencies
65
+ case _ -> Fancy Package install: package_name
66
+ }
63
67
  System exit
64
68
  }
65
69
 
@@ -0,0 +1,19 @@
1
+ class Fancy {
2
+ class MessageSink : BasicObject {
3
+ """
4
+ A MessageSink just swallows all messages that are sent to it.
5
+ """
6
+
7
+ def unknown_message: m with_params: p {
8
+ """
9
+ @m Message sent to @self.
10
+ @p @Array@ of parameters sent along with @m.
11
+ @return @self.
12
+
13
+ Catches all messages and arguments and simply always returns @self.
14
+ """
15
+
16
+ self
17
+ }
18
+ }
19
+ }
@@ -39,6 +39,25 @@ class Number {
39
39
  self
40
40
  }
41
41
 
42
+ def upto: num in_steps_of: steps do: block {
43
+ """
44
+ @num Maximum @Number@ to call @block with.
45
+ @steps @Number@ of numbers to skip each step.
46
+ @block A @Block@ that should be called every @steps steps between @self and @num.
47
+ @return @self
48
+
49
+ Calls @block every @steps steps between @self and @num with the current @Number@.
50
+ Expects @num to be greater or equal to @self.
51
+ """
52
+
53
+ i = self
54
+ while: { i <= num } do: {
55
+ block call: [i]
56
+ i = i + steps
57
+ }
58
+ self
59
+ }
60
+
42
61
  def downto: num {
43
62
  """
44
63
  @num @Number@ to create an @Array@ down to.
@@ -75,6 +94,25 @@ class Number {
75
94
  self
76
95
  }
77
96
 
97
+ def downto: num in_steps_of: steps do: block {
98
+ """
99
+ @num Minimum @Number@ to call @block with.
100
+ @steps @Number@ of numbers to skip each step.
101
+ @block A @Block@ that should be called every @steps steps between @self and @num.
102
+ @return @self
103
+
104
+ Calls @block every @steps steps between @self and @num with the current @Number@.
105
+ Expects @num to be smaller or equal to @self.
106
+ """
107
+
108
+ i = self
109
+ while: { i >= num } do: {
110
+ block call: [i]
111
+ i = i - steps
112
+ }
113
+ self
114
+ }
115
+
78
116
  def squared {
79
117
  """
80
118
  @return Squared value of @self.
@@ -95,6 +133,16 @@ class Number {
95
133
  self + self
96
134
  }
97
135
 
136
+ def cubed {
137
+ """
138
+ @return Cubed value of @self.
139
+
140
+ Returns the cubed value of a Number.
141
+ """
142
+
143
+ self ** 3
144
+ }
145
+
98
146
  def abs {
99
147
  """
100
148
  @return Absolute (positive) value of @self.
@@ -29,9 +29,9 @@ class Object {
29
29
  def println {
30
30
  """
31
31
  Same as:
32
- Console println: self
32
+ *stdout* println: self
33
33
 
34
- Prints @self on @STDOUT, followed by a newline.
34
+ Prints @self on @*stdout*, followed by a newline.
35
35
  """
36
36
 
37
37
  *stdout* println: to_s
@@ -40,9 +40,9 @@ class Object {
40
40
  def print {
41
41
  """
42
42
  Same as:
43
- Console print: self
43
+ *stdout* print: self
44
44
 
45
- Prints @self on STDOUT.
45
+ Prints @self on @*stdout*.
46
46
  """
47
47
 
48
48
  *stdout* print: to_s
@@ -149,19 +149,19 @@ class Object {
149
149
 
150
150
  def to_enum {
151
151
  """
152
- @return @FancyEnumerator@ for @self using 'each: for iteration.
152
+ @return @Fancy::Enumerator@ for @self using 'each: for iteration.
153
153
  """
154
154
 
155
- FancyEnumerator new: self
155
+ Fancy Enumerator new: self
156
156
  }
157
157
 
158
158
  def to_enum: iterator {
159
159
  """
160
160
  @iterator Message to use for iteration on @self.
161
- @return @FancyEnumerator@ for @self using @iterator for iteration.
161
+ @return @Fancy::Enumerator@ for @self using @iterator for iteration.
162
162
  """
163
163
 
164
- FancyEnumerator new: self with: iterator
164
+ Fancy Enumerator new: self with: iterator
165
165
  }
166
166
 
167
167
  def and: other {
@@ -539,11 +539,28 @@ class Object {
539
539
  }
540
540
 
541
541
  def copy_slots: slots from: object {
542
+ """
543
+ @slots @Fancy::Enumerable@ of slot names to copy from @object.
544
+ @object Target @Object@ to copy slots from.
545
+
546
+ Copies slots from @object to @self.
547
+ """
548
+
542
549
  slots each: |s| {
543
550
  set_slot: s value: (object get_slot: s)
544
551
  }
545
552
  }
546
553
 
554
+ def copy_slots_from: object {
555
+ """
556
+ @object @Object@ to copy slots from.
557
+
558
+ Copies all slots from @object to @self.
559
+ """
560
+
561
+ copy_slots: (object slots) from: object
562
+ }
563
+
547
564
  def get_slots: slots {
548
565
  """
549
566
  @slots @Array@ of slot names to retrieve from @self.
@@ -590,14 +607,24 @@ class Object {
590
607
  self
591
608
  }
592
609
 
610
+ def tap: block {
611
+ """
612
+ @block @Block@ to be called with @self.
613
+ @return @self.
614
+
615
+ Calls a given @Block@ with @self before returning @self.
616
+ """
617
+
618
+ block call: [self]
619
+ self
620
+ }
621
+
593
622
  def slots {
594
623
  """
595
- @return @Set@ of slot names that @self has.
624
+ @return @Array@ of slot names that @self has.
596
625
  """
597
626
 
598
- Set new: $ instance_variables map: |s| {
599
- s rest to_sym
600
- }
627
+ instance_variables map: @{ rest to_sym }
601
628
  }
602
629
 
603
630
  def sleep: seconds {
@@ -620,7 +647,7 @@ class Object {
620
647
  Dynamically rebinds @var_name as dynamic variable with @value as the value within @block.
621
648
 
622
649
  Example:
623
- File open: \"/tmp/output.txt\" modes: ['write] with: |f| {
650
+ File write: \"/tmp/output.txt\" with: |f| {
624
651
  let: '*stdout* be: f in: {
625
652
  \"hello, world!\" println # writes it to file not STDOUT
626
653
  }
@@ -638,9 +665,34 @@ class Object {
638
665
  try {
639
666
  Thread current[var_name]: value
640
667
  retval = block call
668
+ } catch Exception => e {
669
+ e raise!
641
670
  } finally {
642
671
  Thread current[var_name]: oldval
643
672
  return retval
644
673
  }
645
674
  }
675
+
676
+ def with_output_to: filename do: block {
677
+ """
678
+ @filename Filename of file to write to.
679
+ @block @Block@ to be executed with *stdout* being bound to the output file.
680
+
681
+ Opens @filename and rebinds `*stdout*` to it within @block.
682
+
683
+ Example:
684
+ with_output_to: \"/tmp/hello_world.txt\" do: {
685
+ \"hello\" println
686
+ \"world\" println
687
+ }
688
+ This writes
689
+ hello
690
+ world
691
+ to /tmp/hello_world.txt
692
+ """
693
+
694
+ File write: filename with: |f| {
695
+ let: '*stdout* be: f in: block
696
+ }
697
+ }
646
698
  }
@@ -1,4 +1,5 @@
1
1
  require: "package/installer"
2
+ require: "package/dependency_installer"
2
3
  require: "package/uninstaller"
3
4
  require: "package/dependency"
4
5
  require: "package/specification"
@@ -29,7 +30,7 @@ class Fancy Package {
29
30
  DEFAULT_PACKAGES_PATH = DEFAULT_FANCY_ROOT ++ "/packages"
30
31
  DEFAULT_PACKAGES_LIB_PATH = DEFAULT_PACKAGES_PATH ++ "/lib"
31
32
 
32
- def self install: package_name {
33
+ def self install: package_name version: version ('latest) {
33
34
  """
34
35
  @package_name Name of package to install.
35
36
 
@@ -39,7 +40,16 @@ class Fancy Package {
39
40
  Which would get the package code from github.com/user/repo
40
41
  """
41
42
 
42
- Installer new: package_name . run
43
+ Installer new: package_name version: version . run
44
+ }
45
+
46
+ def self install_dependencies {
47
+ """
48
+ Installs dependencies found in .fancypack file in the current directory.
49
+ If no .fancypack file is found, fails and quits.
50
+ """
51
+
52
+ DependencyInstaller new run
43
53
  }
44
54
 
45
55
  def self uninstall: package_name {
@@ -20,5 +20,18 @@ class Fancy Package {
20
20
 
21
21
  def initialize: @gem_name version: @version ('latest) {
22
22
  }
23
+
24
+ def install {
25
+ """
26
+ Installs the RubyDependency (a RubyGem) via rbx -S gem on the system.
27
+ """
28
+
29
+ match @version {
30
+ case 'latest ->
31
+ System do: "rbx gem install #{@gem_name}"
32
+ case _ ->
33
+ System do: "rbx gem install -v=#{@version} #{@gem_name}"
34
+ }
35
+ }
23
36
  }
24
37
  }
@@ -0,0 +1,27 @@
1
+ class Fancy {
2
+ class Package {
3
+ class DependencyInstaller {
4
+ def run {
5
+ packfile = Dir glob("*.fancypack") first
6
+ unless: packfile do: {
7
+ *stderr* println: "No .fancypack file found. Quitting."
8
+ return nil
9
+ }
10
+
11
+ require: packfile
12
+
13
+ spec_name = packfile split: ".fancypack" . first
14
+ if: (Specification[spec_name]) then: |s| {
15
+ s dependencies each: |dep| {
16
+ "Installing dependency: #{dep name} (#{dep version})" println
17
+ Fancy Package install: (dep name) version: (dep version)
18
+ }
19
+ s rubygem_dependencies each: |dep| {
20
+ "Installing Ruby dependency: #{dep gem_name} (#{dep version})" println
21
+ dep install
22
+ }
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
@@ -13,10 +13,10 @@ class Fancy Package {
13
13
 
14
14
  """
15
15
 
16
- def initialize: @package_name version: @version ("latest") install_path: @install_path (ENV["FANCY_PACKAGE_DIR"]) {
16
+ def initialize: @package_name version: @version ('latest) install_path: @install_path (ENV["FANCY_PACKAGE_DIR"]) {
17
17
  """
18
18
  Creates a new @Package Installer@ for a given package name, an
19
- optional version (default is 'latest') and an optional
19
+ optional version (default is 'latest) and an optional
20
20
  installation path (default is the standard installation path for
21
21
  Fancy packages).
22
22
  """
@@ -50,7 +50,7 @@ class Fancy Package {
50
50
  """
51
51
 
52
52
  filename = nil
53
- if: (@version == "latest") then: {
53
+ if: (@version == 'latest) then: {
54
54
  if: latest_tag then: |tag| {
55
55
  @version = tag
56
56
  } else: {
@@ -200,13 +200,7 @@ class Fancy Package {
200
200
  Package install: dep
201
201
  }
202
202
 
203
- spec rubygem_dependencies each: |dep| {
204
- if: (dep version == 'latest) then: {
205
- System do: $ "rbx gem install " ++ (dep gem_name)
206
- } else: {
207
- System do: $ "rbx gem install -v=" ++ (dep version) ++ " " ++ (dep gem_name)
208
- }
209
- }
203
+ spec rubygem_dependencies each: |dep| { dep install }
210
204
  }
211
205
  }
212
206
  }
@@ -1,9 +1,7 @@
1
1
  class Fancy Package {
2
2
  class Uninstaller {
3
3
  """
4
-
5
- @Fancy Package@ Uninstaller.
6
-
4
+ @Fancy::Package@ Uninstaller.
7
5
  """
8
6
 
9
7
  def initialize: @package_name {
@@ -2,7 +2,7 @@
2
2
  #include "ruby.h"
3
3
  #include "parser.h"
4
4
 
5
- int yyerror(char *s);
5
+ int yyerror(VALUE self, char *s);
6
6
  %}
7
7
 
8
8
  %option yylineno
@@ -54,7 +54,7 @@ identifier @?@?({lower}|[_&*])({letter}|{digit}|{special_under})*
54
54
  selector ({letter}|[_&*])({letter}|{digit}|{special_under})*":"
55
55
  constant {capital}({letter}|{digit}|{special_under})*
56
56
  nested_constant ({constant}::)+{constant}
57
- symbol_lit \'({identifier}|{operator}|{constant}|:|"[]"|"|")+
57
+ symbol_lit \'({identifier}|{operator}|{constant}|:|"[]"|"|"|".")+
58
58
  ruby_send_open ({constant}|{identifier}){lparen}
59
59
  ruby_oper_open {operator}{lparen}
60
60
  regexp_lit "/".*"/"
@@ -186,5 +186,10 @@ escaped_newline "\\".*\n
186
186
  {escaped_newline} {}
187
187
  [\n] { return NL; }
188
188
 
189
- . { fprintf(stderr, "SCANNER %d", yyerror("")); exit(1); }
189
+ . {
190
+ fprintf(stderr, "Invalid token: %s\n", yytext);
191
+ VALUE fancy = rb_const_get(rb_cObject, rb_intern("Fancy"));
192
+ VALUE parser = rb_const_get(fancy, rb_intern("Parser"));
193
+ yyerror(parser, yytext);
194
+ }
190
195
 
@@ -273,6 +273,9 @@ identifier: IDENTIFIER {
273
273
  | CLASS {
274
274
  $$ = fy_terminal_node_from(self, "ast:identifier:", "class");
275
275
  }
276
+ | RETURN {
277
+ $$ = fy_terminal_node_from(self, "ast:identifier:", "return");
278
+ }
276
279
  ;
277
280
 
278
281
  any_identifier: const_identifier
@@ -821,7 +824,7 @@ VALUE fy_terminal_node_from(VALUE self, char* method, char* text) {
821
824
 
822
825
  int yyerror(VALUE self, char *s)
823
826
  {
824
- rb_funcall(self, rb_intern("ast:parse_error:"), 2, INT2NUM(yylineno), rb_str_new2(yytext));
827
+ rb_funcall(self, rb_intern("ast:parse_error:"), 2, INT2NUM(yylineno), rb_str_new2(s));
825
828
  return 1;
826
829
  }
827
830
 
@@ -13,9 +13,13 @@ class Fancy {
13
13
  new: filename line: line . parse_string: code . script
14
14
  }
15
15
 
16
+ def self ast: line parse_error: text {
17
+ ParseError new: line message: text filename: (Thread current['__fancy__parser__filename__]) . raise!
18
+ }
19
+
16
20
  read_write_slots: ['filename, 'line, 'script]
17
21
 
18
- def initialize: @filename line: @line { }
22
+ def initialize: @filename line: @line { Thread current['__fancy__parser__filename__]: @filename }
19
23
 
20
24
  def body: body {
21
25
  @script = AST Script new: @line file: @filename body: body
@@ -69,7 +73,7 @@ class Fancy {
69
73
  # TODO: Clean this up or make it simpler...
70
74
 
71
75
  # this case handles string interpolation
72
- case /(.*)#{(.*)}(.*)/ -> |matches|
76
+ case /(.*)#{(.*)}(.*)/m -> |matches|
73
77
  prefix = matches[1]
74
78
  interpol_str = matches[2]
75
79
  suffix = matches[3]
@@ -78,7 +82,7 @@ class Fancy {
78
82
  suffix_str = ast: line string: (" " + suffix + " ")
79
83
  interpol_ast = AST StringInterpolation new: line code: interpol_str
80
84
  # create messagesend to concatenate:
81
- concat_ident = ast: line identifier: "++"
85
+ concat_ident = ast: line identifier: "<<"
82
86
  interpol_send = AST MessageSend new: line message: concat_ident to: prefix_str args: (AST MessageArgs new: line args: [interpol_ast])
83
87
 
84
88
  # don't concatenate suffix if it's empty..