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
@@ -0,0 +1,33 @@
1
+ class Fancy AST {
2
+ class ClassDef : Rubinius AST Class {
3
+ def initialize: @line name: @name parent: @parent body: @body {
4
+ name = nil
5
+ if: (@name is_a?: NestedConstant) then: {
6
+ name = @name scoped
7
+ } else: {
8
+ name = @name string to_sym()
9
+ }
10
+
11
+ if: (@body empty?) then: {
12
+ @body unshift_expression: $ NilLiteral new: @line
13
+ }
14
+
15
+ initialize(@line, name, @parent, @body)
16
+ }
17
+
18
+ def bytecode: g {
19
+ pos(g)
20
+ docstring = body() body() shift_docstring
21
+ docstring if_do: {
22
+ setdoc = MessageSend new: @line \
23
+ message: (Identifier from: "for:append:" line: @line) \
24
+ to: (Identifier from: "Fancy::Documentation" line: @line) \
25
+ args: (MessageArgs new: @line args: [Self new: @line, docstring])
26
+
27
+ # Replace first string expression to set documentation.
28
+ body() body() unshift_expression: setdoc
29
+ }
30
+ bytecode(g)
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,47 @@
1
+ class Fancy AST {
2
+
3
+ class ExpressionList : Node {
4
+ read_slots: ['expressions]
5
+ def initialize: @line list: @expressions ([]) {}
6
+
7
+ def unshift_expression: expression {
8
+ @expressions unshift(expression)
9
+ }
10
+
11
+ def add_expression: expression {
12
+ @expressions << expression
13
+ }
14
+
15
+ def empty? {
16
+ @expressions empty?
17
+ }
18
+
19
+ def bytecode: g {
20
+ pos(g)
21
+ size = @expressions size
22
+ @expressions each: |expr| {
23
+ size = size - 1
24
+ expr bytecode: g
25
+ { g pop() } if: (size > 0)
26
+ }
27
+ }
28
+
29
+ # This method is only used by Rubinius' compiler classes and
30
+ # defined to be able to use their bytecode generation toolchain.
31
+ def strip_arguments {
32
+ []
33
+ }
34
+
35
+ # If this expression list contains more than one expression
36
+ # and the first one is an string literal, it'll be used as doc.
37
+ # This method removes the first documentation string.
38
+ def shift_docstring {
39
+ if: ((@expressions first kind_of?(Rubinius AST StringLiteral)) && \
40
+ (@expressions size > 1)) then: {
41
+ @expressions shift()
42
+ }
43
+ }
44
+
45
+ }
46
+
47
+ }
@@ -0,0 +1,113 @@
1
+ class Fancy AST {
2
+
3
+ class Identifier : Node {
4
+ read_slots: ['string, 'line]
5
+ read_write_slots: ['ruby_ident]
6
+
7
+ @@gen_ident_start = 0
8
+
9
+ def Identifier generate: line {
10
+ """
11
+ @line Line to be set for generated Identifier.
12
+ @return New generated Identifier, e.g. \"______gen_ident______1\"
13
+
14
+ Generates a new Identifier using a simple counter.
15
+ """
16
+
17
+ @@gen_ident_start = @@gen_ident_start + 1
18
+ Identifier from: ("______gen_ident______" ++ @@gen_ident_start) line: line
19
+ }
20
+
21
+ def initialize: @line string: @string ruby_ident: @ruby_ident (false) {}
22
+
23
+ def name {
24
+ @string to_sym()
25
+ }
26
+
27
+ def method_name: receiver ruby_send: ruby (false) {
28
+ ruby || @ruby_ident if_do: {
29
+ @string to_sym()
30
+ } else: {
31
+ @string =~ /:$/ . if_do: {
32
+ @string to_sym()
33
+ } else: {
34
+ ":" + @string . to_sym()
35
+ }
36
+ }
37
+ }
38
+
39
+ def self from: string line: line filename: filename (nil) {
40
+ type = match string -> {
41
+ case "__FILE__" -> return CurrentFile new: line filename: filename
42
+ case "__LINE__" -> return CurrentLine new: line
43
+ case "self" -> return Self new: line
44
+ case /^[A-Z].*::/ -> NestedConstant
45
+ case /^[A-Z]/ -> Constant
46
+ case /^@@/ -> ClassVariable
47
+ case /^@/ -> InstanceVariable
48
+ case _ -> Identifier
49
+ }
50
+ type new: line string: string
51
+ }
52
+
53
+ def bytecode: g {
54
+ pos(g)
55
+ match @string -> {
56
+ case "true" -> g push_true()
57
+ case "false" -> g push_false()
58
+ case "nil" -> g push_nil()
59
+ case _ -> Rubinius AST LocalVariableAccess new(@line, self name) bytecode(g)
60
+ }
61
+ }
62
+ }
63
+
64
+ class InstanceVariable : Identifier {
65
+ def initialize: @line string: @string {}
66
+ def bytecode: g {
67
+ pos(g)
68
+ Rubinius AST InstanceVariableAccess new(@line, self name) bytecode(g)
69
+ }
70
+ }
71
+
72
+ class ClassVariable : Identifier {
73
+ def initialize: @line string: @string {}
74
+ def bytecode: g {
75
+ pos(g)
76
+ Rubinius AST ClassVariableAccess new(@line, self name) bytecode(g)
77
+ }
78
+ }
79
+
80
+ class Constant : Identifier {
81
+ def initialize: @line string: @string {}
82
+ def bytecode: g {
83
+ pos(g)
84
+ Rubinius AST ConstantAccess new(@line, self name) bytecode(g)
85
+ }
86
+ }
87
+
88
+ class NestedConstant : Identifier {
89
+ def initialize: @line string: @string {
90
+ }
91
+
92
+ def initialize: @line const: const parent: parent {
93
+ @string = (parent string) ++ "::" ++ (const string)
94
+ }
95
+
96
+ def scoped {
97
+ names = @string split("::")
98
+ parent = Constant new: @line string: (names shift())
99
+ scoped = nil
100
+ names each() |name| {
101
+ scoped = Rubinius AST ScopedConstant new(@line, parent, name to_sym())
102
+ parent = scoped
103
+ }
104
+ scoped
105
+ }
106
+
107
+ def bytecode: g {
108
+ pos(g)
109
+ self scoped bytecode(g)
110
+ }
111
+ }
112
+
113
+ }
@@ -0,0 +1,122 @@
1
+ class Fancy AST {
2
+ class NilLiteral : Rubinius AST NilLiteral {
3
+ def initialize: line { initialize(line) }
4
+ def bytecode: g {
5
+ pos(g)
6
+ bytecode(g)
7
+ }
8
+ }
9
+
10
+ class FixnumLiteral : Rubinius AST FixnumLiteral {
11
+ def initialize: line value: value { initialize(line, value) }
12
+ def bytecode: g {
13
+ pos(g)
14
+ bytecode(g)
15
+ }
16
+ }
17
+
18
+ class NumberLiteral : Rubinius AST NumberLiteral {
19
+ def initialize: line value: value { initialize(line, value) }
20
+ def bytecode: g {
21
+ pos(g)
22
+ bytecode(g)
23
+ }
24
+ }
25
+
26
+ class StringLiteral : Rubinius AST StringLiteral {
27
+ def initialize: line value: value { initialize(line, StringHelper unescape_string(value)) }
28
+ def bytecode: g {
29
+ pos(g)
30
+ bytecode(g)
31
+ }
32
+ }
33
+
34
+ class CurrentFile : Node {
35
+ def initialize: @line filename: @filename { }
36
+ def bytecode: g {
37
+ pos(g)
38
+ args = MessageArgs new: @line args: [StringLiteral new: @line value: @filename]
39
+ MessageSend new: @line message: (Identifier from: "current_file:" line: @line) \
40
+ to: (Identifier from: "Fancy::CodeLoader" line: @line) \
41
+ args: args .
42
+ bytecode: g
43
+ }
44
+ }
45
+
46
+ class CurrentLine : Node {
47
+ def initialize: @line {}
48
+ def bytecode: g {
49
+ pos(g)
50
+ FixnumLiteral new: @line value: @line . bytecode: g
51
+ }
52
+ }
53
+
54
+ class Nothing : Node {
55
+ def initialize: @line { }
56
+ def bytecode: g { pos(g) }
57
+ }
58
+
59
+ class StackTop : Node {
60
+ def initialize: @line { }
61
+ def bytecode: g {
62
+ pos(g)
63
+ g dup()
64
+ }
65
+ }
66
+
67
+ class StackLocal : Node {
68
+ def initialize: @line { }
69
+ def set: g { @local = g new_stack_local(); g set_stack_local(@local) }
70
+ def bytecode: g {
71
+ pos(g)
72
+ g push_stack_local(@local)
73
+ }
74
+ }
75
+
76
+ class Self : Rubinius AST Self {
77
+ def initialize: line { initialize(line) }
78
+ def bytecode: g {
79
+ pos(g)
80
+ bytecode(g)
81
+ }
82
+ }
83
+
84
+ class SymbolLiteral : Rubinius AST SymbolLiteral {
85
+ def initialize: line value: value { initialize(line, value) }
86
+ def bytecode: g {
87
+ pos(g)
88
+ bytecode(g)
89
+ }
90
+ }
91
+
92
+ class RegexpLiteral : Rubinius AST RegexLiteral {
93
+ def initialize: line value: value { initialize(line, value, 0) }
94
+ def bytecode: g {
95
+ pos(g)
96
+ bytecode(g)
97
+ }
98
+ }
99
+
100
+ class ArrayLiteral : Rubinius AST ArrayLiteral {
101
+ read_slots: ['array]
102
+ def initialize: line array: @array {
103
+ @array if_nil: { @array = [] }
104
+ initialize(line, @array)
105
+ }
106
+ def bytecode: g {
107
+ pos(g)
108
+ bytecode(g)
109
+ }
110
+ }
111
+
112
+ class HashLiteral : Rubinius AST HashLiteral {
113
+ def initialize: line entries: @key_values {
114
+ @key_values if_nil: { @key_values = [] }
115
+ initialize(line, @key_values)
116
+ }
117
+ def bytecode: g {
118
+ pos(g)
119
+ bytecode(g)
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,88 @@
1
+ class Fancy AST {
2
+
3
+ class Match : Node {
4
+ def initialize: @line expr: @expr body: @clauses {
5
+ }
6
+
7
+
8
+ def bytecode: g {
9
+ pos(g)
10
+
11
+ # create labels for each clause body.
12
+ clause_labels = []
13
+ @clauses size times: {
14
+ clause_labels << (g new_label())
15
+ }
16
+ end_label = g new_label()
17
+
18
+ # ok, let's emit the bytecode
19
+ @expr bytecode: g
20
+
21
+ @match_arg_vars = []
22
+
23
+ @clauses each_with_index: |c i| {
24
+ g dup() # save the @expr since we need to reuse it
25
+ c expr bytecode: g
26
+ g swap()
27
+ g send(':===, 1)
28
+
29
+ # if match_arg is given, get a localvar slot and set the
30
+ # result of the === call to it
31
+ if: (c match_args first) then: |marg| {
32
+ match_arg_var = g state() scope() new_local(marg)
33
+ @match_arg_vars << match_arg_var
34
+ g set_local(match_arg_var slot())
35
+ }
36
+
37
+ # for any remaining match arguments, set their values to
38
+ # whatever matcher[idx] returns (should be the matched data)
39
+ c match_args rest each_with_index: |match_arg idx| {
40
+ idx = idx + 1 # we only want from index 1 onwards
41
+ g dup() # dup the matcher object
42
+ match_arg_var = g state() scope() new_local(match_arg)
43
+ @match_arg_vars << match_arg_var
44
+ FixnumLiteral new: @line value: idx . bytecode: g
45
+ g send('at:, 1)
46
+ g set_local(match_arg_var slot())
47
+ g pop()
48
+ }
49
+
50
+ g git(clause_labels[i])
51
+ }
52
+ g pop()
53
+ g push_nil()
54
+ g goto(end_label)
55
+
56
+ clause_labels each_with_index: |label i| {
57
+ label set!()
58
+ g pop()
59
+ @clauses[i] body bytecode: g
60
+
61
+ # set match_arg locals slot to nil, so they're only visible
62
+ # within the case body
63
+ @match_arg_vars each: |marg_var| {
64
+ g push_nil()
65
+ g set_local(marg_var slot())
66
+ g pop()
67
+ }
68
+
69
+ g goto(end_label)
70
+ }
71
+
72
+ end_label set!()
73
+ }
74
+ }
75
+
76
+ class MatchClause : Node {
77
+ read_slots: ['expr, 'body, 'match_args]
78
+ def initialize: @line expr: @expr body: @body args: @match_args {
79
+ if: (@expr kind_of?: Identifier) then: {
80
+ if: (@expr string == "_") then: {
81
+ @expr = Identifier from: "Object" line: @line
82
+ }
83
+ }
84
+ @match_args = @match_args map: 'name
85
+ }
86
+ }
87
+
88
+ }
@@ -0,0 +1,110 @@
1
+ class Fancy AST {
2
+
3
+ class MessageSend : Node {
4
+ read_write_slots: ['name, 'receiver, 'args]
5
+ def initialize: @line message: @name to: @receiver args: @args { }
6
+
7
+ def bytecode: g {
8
+ pos(g)
9
+ if: (@receiver is_a?: Super) then: {
10
+ SuperSend new: @line message: @name args: @args . bytecode: g
11
+ } else: {
12
+ @receiver bytecode: g
13
+ @args bytecode: g
14
+ pos(g)
15
+ { g allow_private() } if: (@receiver is_a?: Self)
16
+ sym = @name method_name: @receiver ruby_send: (self ruby_send?)
17
+ if: (self has_splat?) then: {
18
+ { g push_nil() } unless: $ self ruby_block?
19
+ g send_with_splat(sym, @args size, false)
20
+ return nil
21
+ }
22
+ if: (self ruby_block?) then: {
23
+ g send_with_block(sym, @args size, false)
24
+ } else: {
25
+ g send(sym, @args size, false)
26
+ }
27
+ }
28
+ }
29
+
30
+ def ruby_block? {
31
+ @args has_block?
32
+ }
33
+
34
+ def ruby_send? {
35
+ @args ruby_args?
36
+ }
37
+
38
+ def has_splat? {
39
+ @args has_splat?
40
+ }
41
+ }
42
+
43
+ class MessageArgs : Node {
44
+ read_slots: ['args]
45
+ def initialize: @line args: @args { }
46
+
47
+ def bytecode: g {
48
+ pos(g)
49
+ @args each: |a| {
50
+ a bytecode: g
51
+ }
52
+ }
53
+
54
+ def size {
55
+ @args size
56
+ }
57
+
58
+ def ruby_args? {
59
+ is_a?: RubyArgs
60
+ }
61
+
62
+ def has_block? {
63
+ false
64
+ }
65
+
66
+ def has_splat? {
67
+ false
68
+ }
69
+ }
70
+
71
+
72
+ class RubyArgs : MessageArgs {
73
+ def initialize: @line args: @args block: @block (nil) {
74
+ { @args = @args array } unless: (@args is_a?: Array)
75
+ @block if_nil: {
76
+ if: (@args last kind_of?: Identifier) then: {
77
+ if: (@args last string =~ /^&\w/) then: {
78
+ @block = @args pop()
79
+ @block = Identifier new: (@block line) string: (@block string from: 1 to: -1)
80
+ }
81
+ }
82
+ }
83
+
84
+ if: (@args last kind_of?: Identifier) then: {
85
+ if: (@args last string =~ /^\*\w/) then: {
86
+ @splat = @args pop()
87
+ @splat = Identifier new: (@splat line) string: (@splat string from: 1 to: -1)
88
+ }
89
+ }
90
+ }
91
+
92
+ def bytecode: g {
93
+ pos(g)
94
+ @args each: |a| {
95
+ a bytecode: g
96
+ }
97
+ { @splat bytecode: g; g cast_array() } if: @splat
98
+ { @block bytecode: g } if: @block
99
+ }
100
+
101
+ def has_block? {
102
+ @block nil? not
103
+ }
104
+
105
+ def has_splat? {
106
+ @splat nil? not
107
+ }
108
+ }
109
+
110
+ }