fancy 0.3.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 (242) hide show
  1. data/AUTHORS +7 -0
  2. data/LICENSE +19 -0
  3. data/README +173 -0
  4. data/Rakefile +255 -0
  5. data/bin/fancy +40 -0
  6. data/bin/fdoc +23 -0
  7. data/bin/fyi +22 -0
  8. data/bin/ifancy +46 -0
  9. data/boot/README +12 -0
  10. data/boot/code_loader.rb +165 -0
  11. data/boot/compile.fy +3 -0
  12. data/boot/fancy_ext.rb +13 -0
  13. data/boot/fancy_ext/block_env.rb +29 -0
  14. data/boot/fancy_ext/class.rb +26 -0
  15. data/boot/fancy_ext/kernel.rb +12 -0
  16. data/boot/fancy_ext/module.rb +89 -0
  17. data/boot/fancy_ext/object.rb +34 -0
  18. data/boot/fancy_ext/string_helper.rb +10 -0
  19. data/boot/load.rb +72 -0
  20. data/boot/rbx-compiler/README +12 -0
  21. data/boot/rbx-compiler/compiler.rb +24 -0
  22. data/boot/rbx-compiler/compiler/ast.rb +23 -0
  23. data/boot/rbx-compiler/compiler/ast/README +11 -0
  24. data/boot/rbx-compiler/compiler/ast/array_literal.rb +13 -0
  25. data/boot/rbx-compiler/compiler/ast/assign.rb +57 -0
  26. data/boot/rbx-compiler/compiler/ast/block.rb +70 -0
  27. data/boot/rbx-compiler/compiler/ast/class_def.rb +35 -0
  28. data/boot/rbx-compiler/compiler/ast/expression_list.rb +57 -0
  29. data/boot/rbx-compiler/compiler/ast/hash_literal.rb +11 -0
  30. data/boot/rbx-compiler/compiler/ast/identifier.rb +120 -0
  31. data/boot/rbx-compiler/compiler/ast/match.rb +81 -0
  32. data/boot/rbx-compiler/compiler/ast/message_send.rb +71 -0
  33. data/boot/rbx-compiler/compiler/ast/method_def.rb +116 -0
  34. data/boot/rbx-compiler/compiler/ast/node.rb +6 -0
  35. data/boot/rbx-compiler/compiler/ast/range_literal.rb +22 -0
  36. data/boot/rbx-compiler/compiler/ast/require.rb +20 -0
  37. data/boot/rbx-compiler/compiler/ast/return.rb +29 -0
  38. data/boot/rbx-compiler/compiler/ast/ruby_args.rb +35 -0
  39. data/boot/rbx-compiler/compiler/ast/script.rb +56 -0
  40. data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +39 -0
  41. data/boot/rbx-compiler/compiler/ast/string_literal.rb +14 -0
  42. data/boot/rbx-compiler/compiler/ast/super.rb +25 -0
  43. data/boot/rbx-compiler/compiler/ast/try_catch_block.rb +220 -0
  44. data/boot/rbx-compiler/compiler/ast/tuple_literal.rb +33 -0
  45. data/boot/rbx-compiler/compiler/command.rb +39 -0
  46. data/boot/rbx-compiler/compiler/compiler.rb +83 -0
  47. data/boot/rbx-compiler/compiler/stages.rb +99 -0
  48. data/boot/rbx-compiler/parser.rb +2 -0
  49. data/boot/rbx-compiler/parser/README +15 -0
  50. data/boot/rbx-compiler/parser/Rakefile +54 -0
  51. data/boot/rbx-compiler/parser/extconf.rb +3 -0
  52. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  53. data/boot/rbx-compiler/parser/fancy_parser.c +46 -0
  54. data/boot/rbx-compiler/parser/fancy_parser.h +8 -0
  55. data/boot/rbx-compiler/parser/lexer.lex +180 -0
  56. data/boot/rbx-compiler/parser/parser.rb +356 -0
  57. data/boot/rbx-compiler/parser/parser.y +711 -0
  58. data/boot/rsexp_pretty_printer.rb +76 -0
  59. data/doc/api/fancy.css +93 -0
  60. data/doc/api/fancy.jsonp +1 -0
  61. data/doc/api/fdoc.js +187 -0
  62. data/doc/api/index.html +57 -0
  63. data/doc/api/underscore-min.js +18 -0
  64. data/doc/features.md +228 -0
  65. data/examples/argv.fy +8 -0
  66. data/examples/arithmetic.fy +7 -0
  67. data/examples/armstrong_numbers.fy +33 -0
  68. data/examples/array.fy +52 -0
  69. data/examples/blocks.fy +15 -0
  70. data/examples/boolean.fy +24 -0
  71. data/examples/call_with_receiver.fy +9 -0
  72. data/examples/class.fy +68 -0
  73. data/examples/closures.fy +24 -0
  74. data/examples/constant_access.fy +15 -0
  75. data/examples/default_args.fy +17 -0
  76. data/examples/define_methods.fy +15 -0
  77. data/examples/documentation.fy +57 -0
  78. data/examples/documentation_formatters.fy +25 -0
  79. data/examples/echo.fy +16 -0
  80. data/examples/empty_catch.fy +4 -0
  81. data/examples/exception.fy +9 -0
  82. data/examples/factorial.fy +12 -0
  83. data/examples/fibonacci.fy +16 -0
  84. data/examples/files.fy +23 -0
  85. data/examples/finally.fy +5 -0
  86. data/examples/game_of_life.fy +148 -0
  87. data/examples/hashes.fy +7 -0
  88. data/examples/hello_world.fy +6 -0
  89. data/examples/html_generator.fy +54 -0
  90. data/examples/implicit_return.fy +3 -0
  91. data/examples/matchers.fy +6 -0
  92. data/examples/methods.fy +29 -0
  93. data/examples/nested_classes.fy +27 -0
  94. data/examples/nested_try.fy +9 -0
  95. data/examples/numbers.fy +12 -0
  96. data/examples/pattern_matching.fy +40 -0
  97. data/examples/person.fy +65 -0
  98. data/examples/project-euler/01.fy +8 -0
  99. data/examples/project-euler/02.fy +21 -0
  100. data/examples/project-euler/28.fy +33 -0
  101. data/examples/rbx/and_or.fy +7 -0
  102. data/examples/rbx/blocks.fy +22 -0
  103. data/examples/rbx/classes.fy +32 -0
  104. data/examples/rbx/hello.fy +8 -0
  105. data/examples/rbx/include.fy +12 -0
  106. data/examples/rbx/inherit.fy +11 -0
  107. data/examples/rbx/methods.fy +15 -0
  108. data/examples/rbx/nested_classes.fy +9 -0
  109. data/examples/rbx/require.fy +3 -0
  110. data/examples/rbx/strings.fy +5 -0
  111. data/examples/regex.fy +7 -0
  112. data/examples/require.fy +7 -0
  113. data/examples/retry.fy +12 -0
  114. data/examples/return.fy +13 -0
  115. data/examples/ruby_require.fy +7 -0
  116. data/examples/ruby_send.fy +3 -0
  117. data/examples/singleton_methods.fy +21 -0
  118. data/examples/stupid_quicksort.fy +12 -0
  119. data/examples/threads.fy +18 -0
  120. data/examples/tuple.fy +8 -0
  121. data/examples/webserver/webserver.fy +18 -0
  122. data/lib/argv.fy +36 -0
  123. data/lib/array.fy +207 -0
  124. data/lib/block.fy +88 -0
  125. data/lib/boot.fy +41 -0
  126. data/lib/class.fy +106 -0
  127. data/lib/compiler.fy +14 -0
  128. data/lib/compiler/ast.fy +40 -0
  129. data/lib/compiler/ast/assign.fy +96 -0
  130. data/lib/compiler/ast/block.fy +84 -0
  131. data/lib/compiler/ast/class_def.fy +33 -0
  132. data/lib/compiler/ast/expression_list.fy +47 -0
  133. data/lib/compiler/ast/identifier.fy +113 -0
  134. data/lib/compiler/ast/literals.fy +122 -0
  135. data/lib/compiler/ast/match.fy +88 -0
  136. data/lib/compiler/ast/message_send.fy +110 -0
  137. data/lib/compiler/ast/method_def.fy +90 -0
  138. data/lib/compiler/ast/node.fy +7 -0
  139. data/lib/compiler/ast/range.fy +16 -0
  140. data/lib/compiler/ast/require.fy +15 -0
  141. data/lib/compiler/ast/return.fy +23 -0
  142. data/lib/compiler/ast/script.fy +52 -0
  143. data/lib/compiler/ast/singleton_method_def.fy +35 -0
  144. data/lib/compiler/ast/super.fy +17 -0
  145. data/lib/compiler/ast/try_catch.fy +176 -0
  146. data/lib/compiler/ast/tuple_literal.fy +34 -0
  147. data/lib/compiler/command.fy +51 -0
  148. data/lib/compiler/compiler.fy +73 -0
  149. data/lib/compiler/stages.fy +81 -0
  150. data/lib/directory.fy +17 -0
  151. data/lib/documentation.fy +115 -0
  152. data/lib/enumerable.fy +269 -0
  153. data/lib/eval.fy +31 -0
  154. data/lib/fancy_spec.fy +202 -0
  155. data/lib/fdoc.fy +359 -0
  156. data/lib/fdoc_hook.fy +10 -0
  157. data/lib/file.fy +54 -0
  158. data/lib/hash.fy +56 -0
  159. data/lib/main.fy +80 -0
  160. data/lib/method.fy +22 -0
  161. data/lib/nil_class.fy +56 -0
  162. data/lib/number.fy +87 -0
  163. data/lib/object.fy +170 -0
  164. data/lib/package.fy +61 -0
  165. data/lib/package/dependency.fy +24 -0
  166. data/lib/package/installer.fy +180 -0
  167. data/lib/package/specification.fy +55 -0
  168. data/lib/package/uninstaller.fy +15 -0
  169. data/lib/parser.fy +4 -0
  170. data/lib/parser/ext/README +15 -0
  171. data/lib/parser/ext/ext.c +42 -0
  172. data/lib/parser/ext/ext.h +8 -0
  173. data/lib/parser/ext/extconf.rb +3 -0
  174. data/lib/parser/ext/lexer.lex +187 -0
  175. data/lib/parser/ext/parser.y +744 -0
  176. data/lib/parser/methods.fy +297 -0
  177. data/lib/rbx.fy +37 -0
  178. data/lib/rbx/array.fy +237 -0
  179. data/lib/rbx/bignum.fy +23 -0
  180. data/lib/rbx/block.fy +9 -0
  181. data/lib/rbx/class.fy +129 -0
  182. data/lib/rbx/code_loader.fy +192 -0
  183. data/lib/rbx/console.fy +63 -0
  184. data/lib/rbx/directory.fy +46 -0
  185. data/lib/rbx/documentation.fy +64 -0
  186. data/lib/rbx/environment_variables.fy +3 -0
  187. data/lib/rbx/exception.fy +30 -0
  188. data/lib/rbx/false_class.fy +58 -0
  189. data/lib/rbx/fiber.fy +25 -0
  190. data/lib/rbx/file.fy +191 -0
  191. data/lib/rbx/fixnum.fy +25 -0
  192. data/lib/rbx/float.fy +14 -0
  193. data/lib/rbx/hash.fy +38 -0
  194. data/lib/rbx/integer.fy +15 -0
  195. data/lib/rbx/io.fy +30 -0
  196. data/lib/rbx/match_data.fy +9 -0
  197. data/lib/rbx/method.fy +22 -0
  198. data/lib/rbx/name_error.fy +3 -0
  199. data/lib/rbx/no_method_error.fy +15 -0
  200. data/lib/rbx/object.fy +117 -0
  201. data/lib/rbx/range.fy +15 -0
  202. data/lib/rbx/regexp.fy +9 -0
  203. data/lib/rbx/string.fy +63 -0
  204. data/lib/rbx/symbol.fy +12 -0
  205. data/lib/rbx/system.fy +37 -0
  206. data/lib/rbx/tcp_server.fy +6 -0
  207. data/lib/rbx/tcp_socket.fy +7 -0
  208. data/lib/rbx/thread.fy +75 -0
  209. data/lib/rbx/tuple.fy +37 -0
  210. data/lib/set.fy +61 -0
  211. data/lib/stack.fy +51 -0
  212. data/lib/string.fy +58 -0
  213. data/lib/struct.fy +13 -0
  214. data/lib/symbol.fy +23 -0
  215. data/lib/true_class.fy +43 -0
  216. data/lib/tuple.fy +68 -0
  217. data/lib/version.fy +6 -0
  218. data/tests/argv.fy +13 -0
  219. data/tests/array.fy +343 -0
  220. data/tests/assignment.fy +53 -0
  221. data/tests/block.fy +103 -0
  222. data/tests/class.fy +409 -0
  223. data/tests/control_flow.fy +79 -0
  224. data/tests/documentation.fy +24 -0
  225. data/tests/exception.fy +115 -0
  226. data/tests/file.fy +86 -0
  227. data/tests/hash.fy +101 -0
  228. data/tests/method.fy +131 -0
  229. data/tests/nil_class.fy +55 -0
  230. data/tests/number.fy +128 -0
  231. data/tests/object.fy +125 -0
  232. data/tests/parsing/sexp.fy +50 -0
  233. data/tests/pattern_matching.fy +82 -0
  234. data/tests/range.fy +11 -0
  235. data/tests/set.fy +10 -0
  236. data/tests/stack.fy +22 -0
  237. data/tests/string.fy +102 -0
  238. data/tests/symbol.fy +17 -0
  239. data/tests/true_class.fy +63 -0
  240. data/tests/tuple.fy +21 -0
  241. data/tools/fancy-mode.el +63 -0
  242. metadata +321 -0
data/lib/block.fy ADDED
@@ -0,0 +1,88 @@
1
+ class Block {
2
+ """
3
+ The Block class (also BlockEnvironment) is the class of all
4
+ Block-literal values.
5
+ A Block is a piece of unevaluated code, that can be passed around as
6
+ any other value and evaluated by calling the +call+ or +call:+ methods.
7
+
8
+ Blocks also work properly with their enclosing environment in that
9
+ they preserve any local variables that get used within the Block,
10
+ even if the context in which they got defined has been destroyed.
11
+ => Blocks are proper closures.
12
+
13
+ See: http://en.wikipedia.org/wiki/Closure_(computer_science) for
14
+ more information.
15
+ """
16
+
17
+ def while_false: block {
18
+ """
19
+ Executes a given Block while self evals to nil
20
+ Example:
21
+ i = 0
22
+ { i >= 10 } while_false: {
23
+ i println
24
+ i = i + 1
25
+ }
26
+ """
27
+
28
+ { self call not } while_true: block
29
+ }
30
+
31
+ def while_nil: block {
32
+ "Same as Block#while_false:"
33
+
34
+ while_false: block
35
+ }
36
+
37
+ alias_method: 'while_do: for: 'while_true:
38
+
39
+ def until_do: block {
40
+ """
41
+ Calls a given Block as long as @self returns @nil or @false.
42
+ """
43
+
44
+ loop: {
45
+ self call if_do: |val| {
46
+ return val
47
+ } else: {
48
+ block call
49
+ }
50
+ }
51
+ }
52
+
53
+ def && other_block {
54
+ """
55
+ Short-circuiting && (boolean AND).
56
+ """
57
+
58
+ if: (self call) then: {
59
+ other_block call
60
+ } else: {
61
+ return false
62
+ }
63
+ }
64
+
65
+ def || other_block {
66
+ """
67
+ Short-circuiting || (boolean OR).
68
+ """
69
+
70
+ if: (self call) then: {
71
+ return true
72
+ } else: {
73
+ other_block call
74
+ }
75
+ }
76
+
77
+ def if: obj {
78
+ "Calls itself if the given object is true-ish."
79
+
80
+ if: obj then: { self call }
81
+ }
82
+
83
+ def unless: obj {
84
+ "Opposite of Block#if:. Calls itself if the given object is false-ish."
85
+
86
+ unless: obj do: { self call }
87
+ }
88
+ }
data/lib/boot.fy ADDED
@@ -0,0 +1,41 @@
1
+ # boot.fnc
2
+ # This file gets loaded & run by Fancy automatically.
3
+ # It loads in Fancy's standard library & core classes.
4
+
5
+ # NOTE:
6
+ # Order DOES matter here, so watch out what you're doing.
7
+ # In general, it's best to add any autoload-files at the end of the
8
+ # current list (if adding them here is really necessary at all).
9
+
10
+ # rbx.fy loads all the files in lib/rbx/ in the correct order, which
11
+ # define all the functionality to let fancy run on rbx.
12
+ # also, they might override functionality defined in lib/ to reuse
13
+ # existing ruby methods etc.
14
+ require: "rbx.fy"
15
+
16
+ require: "object"
17
+ require: "class"
18
+ require: "true_class"
19
+ require: "nil_class"
20
+ require: "number"
21
+ require: "enumerable"
22
+ require: "string"
23
+ require: "array"
24
+ require: "tuple"
25
+ require: "block"
26
+ require: "file"
27
+ require: "directory"
28
+ require: "fancy_spec"
29
+ require: "hash"
30
+ require: "set"
31
+ require: "symbol"
32
+ require: "method"
33
+ require: "stack"
34
+
35
+ # version holds fancy's version number
36
+ require: "version"
37
+ require: "argv"
38
+
39
+ require: "documentation"
40
+
41
+ require: "package.fy"
data/lib/class.fy ADDED
@@ -0,0 +1,106 @@
1
+ class Class {
2
+ """
3
+ This class is the class of @Class@ objects - e.g. @Object@, @Array@,
4
+ @String@ etc.
5
+ Any class in the language is an instance of this class, as in Ruby
6
+ or Smalltalk.
7
+ """
8
+
9
+ def define_slot_reader: slotname {
10
+ """
11
+ @slotname Name of the slot to define a getter method for.
12
+
13
+ Defines a slot reader method with a given name.
14
+ E.g. for a slotname @count it will define the following method:
15
+ def count {
16
+ get_slot: 'count
17
+ }
18
+ """
19
+
20
+ define_method: slotname with: {
21
+ get_slot: slotname
22
+ }
23
+ }
24
+
25
+ def define_slot_writer: slotname {
26
+ """
27
+ @slotname Name of the slot to defnie define a setter method for.
28
+
29
+ Defines a slot writer method with a given name.
30
+ E.g. for a slotname @count it will define the following method:
31
+ def count: c {
32
+ set_slot: 'count value: c
33
+ }
34
+ """
35
+
36
+ define_method: (slotname to_s + ":") with: |val| {
37
+ set_slot: slotname value: val
38
+ }
39
+ }
40
+
41
+ def read_slots: slots {
42
+ """
43
+ @slots @Array@ of slotnames to define getter methods for.
44
+
45
+ Defines slot reader methods for all given slotnames.
46
+ """
47
+
48
+ slots each: |s| {
49
+ define_slot_reader: s
50
+ }
51
+ }
52
+
53
+ def write_slots: slots {
54
+ """
55
+ @slots @Array@ of slotnames to define setter methods for.
56
+
57
+ Defines slot writer methods for all given slotnames.
58
+ """
59
+
60
+ slots each: |s| {
61
+ define_slot_writer: s
62
+ }
63
+ }
64
+
65
+ def read_write_slots: slots {
66
+ """
67
+ @slots @Array@ of slotnames to define getter & setter methods for.
68
+
69
+ Defines slot reader & writer methods for all given slotnames.
70
+ """
71
+
72
+ slots each: |s| {
73
+ define_slot_reader: s
74
+ define_slot_writer: s
75
+ }
76
+ }
77
+
78
+ def subclass?: class_obj {
79
+ """
80
+ @class_obj Class object to check for, if @self is a subclass of @class_obj.
81
+ @return @true, if @self is a subclass of @class_obj, @false otherwise.
82
+
83
+ Indicates, if a Class is a subclass of another Class.
84
+ """
85
+
86
+ if: (self == class_obj) then: {
87
+ true
88
+ } else: {
89
+ # take care of Object class, as Object is its own superclass
90
+ unless: (self superclass nil?) do: {
91
+ self superclass subclass?: class_obj
92
+ }
93
+ }
94
+ }
95
+
96
+ def alias_method: new_method_name for: old_method_name {
97
+ """
98
+ @new_method_name New method name to be used as an alias for @old_method_name.
99
+ @old_method_name Name of method to alias (must exist in the @Class@).
100
+
101
+ Defines an alias method for another method.
102
+ """
103
+
104
+ alias_method_rbx: new_method_name for: old_method_name
105
+ }
106
+ }
data/lib/compiler.fy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env fancy
2
+
3
+ # A Fancy to rbx bytecode compiler.
4
+
5
+ require: "compiler/compiler"
6
+ require: "compiler/stages"
7
+ require: "compiler/ast"
8
+
9
+ require: "parser"
10
+
11
+ if: (__FILE__ == (ARGV[0])) then: {
12
+ require: "compiler/command"
13
+ Fancy Compiler Command run: ARGV
14
+ }
@@ -0,0 +1,40 @@
1
+ """
2
+ AST nodes are an object representation of source files.
3
+
4
+
5
+ For example for a source code containing only the following expression:
6
+
7
+ Console println: hello
8
+
9
+ An AST tree like the following will be created:
10
+
11
+ Script:
12
+ @body: ExpressionList
13
+ @expressions:
14
+ - MessageSend
15
+ @receiver:
16
+ Constant @string: Console
17
+ @name:
18
+ Identifier @string: println:
19
+ @args:
20
+ - Identifier @string: hello
21
+ """
22
+
23
+ require: "ast/node"
24
+ require: "ast/script"
25
+ require: "ast/expression_list"
26
+ require: "ast/identifier"
27
+ require: "ast/message_send"
28
+ require: "ast/method_def"
29
+ require: "ast/singleton_method_def"
30
+ require: "ast/super"
31
+ require: "ast/literals"
32
+ require: "ast/assign"
33
+ require: "ast/block"
34
+ require: "ast/class_def"
35
+ require: "ast/tuple_literal"
36
+ require: "ast/range"
37
+ require: "ast/require"
38
+ require: "ast/match"
39
+ require: "ast/try_catch"
40
+ require: "ast/return"
@@ -0,0 +1,96 @@
1
+ class Fancy AST {
2
+
3
+ class Assignment : Node {
4
+ def initialize: @line var: @lvalue value: @rvalue { }
5
+
6
+ def bytecode: g {
7
+ pos(g)
8
+ @lvalue bytecode: g assign: @rvalue
9
+ }
10
+ }
11
+
12
+ class MultipleAssignment : Node {
13
+ class MultipleAssignmentExpr : Node {
14
+ def initialize: @line index: @index {
15
+ }
16
+
17
+ def bytecode: g {
18
+ pos(g)
19
+ margs = MessageArgs new: @line args: [FixnumLiteral new: @line value: @index]
20
+ recv = StackTop new: @line
21
+ msg = Identifier from: "at:" line: @line
22
+ MessageSend new: @line message: msg to: recv args: margs . bytecode: g
23
+ }
24
+ }
25
+
26
+ class SplatAssignmentExpr : Node {
27
+ def initialize: @line start_index: @start_index {
28
+ }
29
+
30
+ def bytecode: g {
31
+ pos(g)
32
+ margs = MessageArgs new: @line args: [FixnumLiteral new: @line value: @start_index, FixnumLiteral new: @line value: -1]
33
+ recv = StackTop new: @line
34
+ msg = Identifier from: "from:to:" line: @line
35
+ MessageSend new: @line message: msg to: recv args: margs . bytecode: g
36
+ }
37
+ }
38
+
39
+ def initialize: @line var: @idents value: @values {
40
+ }
41
+
42
+ def bytecode: g {
43
+ pos(g)
44
+ if: (@values size > 1) then: {
45
+ ArrayLiteral new: @line array: @values . bytecode: g
46
+ } else: {
47
+ # in this case we just have one value for multi-assign
48
+ # so we expect it to be a collection type and get values by
49
+ # calling "at:" method (see above)
50
+ @values first bytecode: g
51
+ }
52
+
53
+ max_idx = @idents size - 1
54
+ @idents each_with_index: |ident idx| {
55
+ var = ident
56
+ value = MultipleAssignmentExpr new: @line index: idx
57
+ match ident string -> {
58
+ case /^\*/ ->
59
+ value = SplatAssignmentExpr new: @line start_index: idx
60
+ var = Identifier from: (ident string rest) line: (ident line)
61
+ }
62
+ Assignment new: @line var: var value: value . bytecode: g
63
+ g pop()
64
+ }
65
+ }
66
+ }
67
+
68
+ class Identifier {
69
+ def bytecode: g assign: value {
70
+ pos(g)
71
+ Rubinius AST LocalVariableAssignment new(@line, self name, value) bytecode(g)
72
+ }
73
+ }
74
+
75
+ class InstanceVariable {
76
+ def bytecode: g assign: value {
77
+ pos(g)
78
+ Rubinius AST InstanceVariableAssignment new(@line, self name, value) bytecode(g)
79
+ }
80
+ }
81
+
82
+ class ClassVariable {
83
+ def bytecode: g assign: value {
84
+ pos(g)
85
+ Rubinius AST ClassVariableAssignment new(@line, self name, value) bytecode(g)
86
+ }
87
+ }
88
+
89
+ class Constant {
90
+ def bytecode: g assign: value {
91
+ pos(g)
92
+ Rubinius AST ConstantAssignment new(@line, self name, value) bytecode(g)
93
+ }
94
+ }
95
+
96
+ }
@@ -0,0 +1,84 @@
1
+ class Fancy AST {
2
+ class BlockLiteral : Rubinius AST Iter {
3
+ def initialize: @line args: @args body: @body (NilLiteral new: line) partial: @partial (false) {
4
+ if: (@body empty?) then: {
5
+ @body unshift_expression: $ NilLiteral new: @line
6
+ }
7
+ initialize(@line, @args, @body)
8
+ @args create_locals: self
9
+ if: (@args total_args == 0) then: {
10
+ @arguments prelude=(nil)
11
+ }
12
+ if: (@args.total_args > 1) then: {
13
+ @arguments prelude=('multi)
14
+ }
15
+ @arguments required_args=(@args required_args)
16
+
17
+ if: @partial then: {
18
+ first_expr = @body expressions first
19
+
20
+ # if first expression is an identifier, use that as a 0-arg
21
+ # method name to send to new receiver (use a generated symbol
22
+ # name created in lib/parser/methods.fy / Fancy Parser#ast:partial_block:)
23
+ # if first expression is a message send where its receiver is
24
+ # an identifier, use that as the message name in a send to
25
+ # self and use the result as the receiver value for the rest.
26
+ new_receiver = Identifier from: (@args args first to_s) line: @line
27
+ match first_expr -> {
28
+ case Identifier ->
29
+ @body expressions shift()
30
+ @body unshift_expression: $ MessageSend new: @line message: first_expr to: (new_receiver) args: (MessageArgs new: @line args: [])
31
+ case MessageSend ->
32
+ match first_expr receiver -> {
33
+ case Self ->
34
+ first_expr receiver: new_receiver
35
+ case Identifier ->
36
+ first_expr receiver: $ MessageSend new: @line message: (first_expr receiver) to: (new_receiver) args: (MessageArgs new: @line args: [])
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ def bytecode: g {
43
+ pos(g)
44
+ bytecode(g)
45
+ }
46
+ }
47
+
48
+ class BlockArgs : Node {
49
+ read_write_slots: ['args, 'block]
50
+
51
+ def initialize: @line args: @args ([]) {
52
+ @args = @args map: |a| { a name to_sym() }
53
+ }
54
+
55
+ def bytecode: g {
56
+ pos(g)
57
+ if: (@args size > 1) then: {
58
+ @args each_with_index: |a i| {
59
+ g shift_array()
60
+ g set_local(i)
61
+ g pop()
62
+ }
63
+ } else: {
64
+ @args each_with_index: |a i| {
65
+ g set_local(i)
66
+ }
67
+ }
68
+ }
69
+
70
+ def total_args {
71
+ @args size
72
+ }
73
+
74
+ def required_args {
75
+ self total_args
76
+ }
77
+
78
+ def create_locals: block {
79
+ @args each: |a| {
80
+ block new_local(a)
81
+ }
82
+ }
83
+ }
84
+ }