myco 0.1.0.dev → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -7
  2. data/LICENSE +1 -1
  3. data/README.md +79 -0
  4. data/lib/myco/backtrace.rb +1 -1
  5. data/lib/myco/bootstrap/component.rb +78 -39
  6. data/lib/myco/bootstrap/find_constant.rb +12 -1
  7. data/lib/myco/bootstrap/instance.rb +5 -12
  8. data/lib/myco/bootstrap/meme.rb +176 -28
  9. data/lib/myco/bootstrap.my +8 -7
  10. data/lib/myco/code_loader.rb +332 -0
  11. data/lib/myco/command/inoculate.my +83 -0
  12. data/lib/myco/command.my +26 -26
  13. data/lib/myco/core/BasicDecorators.my +62 -0
  14. data/lib/myco/core/BasicObject.my +12 -34
  15. data/lib/myco/core/Decorator.my +1 -0
  16. data/lib/myco/core/FileToplevel.my +0 -3
  17. data/lib/myco/core/Myco.my +4 -0
  18. data/lib/myco/core/Object.my +6 -4
  19. data/lib/myco/eval.rb +17 -18
  20. data/lib/myco/misc.rb +16 -0
  21. data/lib/myco/parser/ast/argument_assembly.rb +76 -0
  22. data/lib/myco/parser/ast/array_assembly.rb +57 -0
  23. data/lib/myco/parser/ast/branch_operator.rb +73 -0
  24. data/lib/myco/parser/ast/constant_access.rb +4 -18
  25. data/lib/myco/parser/ast/constant_define.rb +3 -3
  26. data/lib/myco/parser/ast/constant_reopen.rb +12 -13
  27. data/lib/myco/parser/ast/declare_category.rb +8 -6
  28. data/lib/myco/parser/ast/declare_decorator.rb +4 -4
  29. data/lib/myco/parser/ast/declare_file.rb +4 -4
  30. data/lib/myco/parser/ast/declare_meme.rb +53 -11
  31. data/lib/myco/parser/ast/declare_object.rb +9 -7
  32. data/lib/myco/parser/ast/declare_string.rb +5 -5
  33. data/lib/myco/parser/ast/invoke.rb +18 -36
  34. data/lib/myco/parser/ast/invoke_method.rb +28 -0
  35. data/lib/myco/parser/ast/local_variable_access_ambiguous.rb +9 -13
  36. data/lib/myco/parser/ast/misc.rb +128 -33
  37. data/lib/myco/parser/ast/myco_module_scope.rb +26 -0
  38. data/lib/myco/parser/ast/quest.rb +3 -3
  39. data/lib/myco/parser/ast/to_ruby/array_assembly.rb +15 -0
  40. data/lib/myco/parser/ast/to_ruby/block.rb +14 -0
  41. data/lib/myco/parser/ast/to_ruby/block_pass.rb +6 -0
  42. data/lib/myco/parser/ast/to_ruby/branch_operator.rb +9 -0
  43. data/lib/myco/parser/ast/to_ruby/constant_access.rb +10 -0
  44. data/lib/myco/parser/ast/to_ruby/constant_assignment.rb +6 -0
  45. data/lib/myco/parser/ast/to_ruby/constant_define.rb +9 -0
  46. data/lib/myco/parser/ast/to_ruby/constant_reopen.rb +6 -0
  47. data/lib/myco/parser/ast/to_ruby/declare_category.rb +7 -0
  48. data/lib/myco/parser/ast/to_ruby/declare_decorator.rb +6 -0
  49. data/lib/myco/parser/ast/to_ruby/declare_file.rb +6 -0
  50. data/lib/myco/parser/ast/to_ruby/declare_meme.rb +16 -0
  51. data/lib/myco/parser/ast/to_ruby/declare_object.rb +8 -0
  52. data/lib/myco/parser/ast/to_ruby/declare_string.rb +6 -0
  53. data/lib/myco/parser/ast/to_ruby/dynamic_string.rb +14 -0
  54. data/lib/myco/parser/ast/to_ruby/dynamic_symbol.rb +7 -0
  55. data/lib/myco/parser/ast/to_ruby/eval_expression.rb +6 -0
  56. data/lib/myco/parser/ast/to_ruby/false_literal.rb +6 -0
  57. data/lib/myco/parser/ast/to_ruby/hash_literal.rb +16 -0
  58. data/lib/myco/parser/ast/to_ruby/invoke.rb +6 -0
  59. data/lib/myco/parser/ast/to_ruby/invoke_method.rb +35 -0
  60. data/lib/myco/parser/ast/to_ruby/iter.rb +10 -0
  61. data/lib/myco/parser/ast/to_ruby/local_variable_access_ambiguous.rb +16 -0
  62. data/lib/myco/parser/ast/to_ruby/local_variable_assignment.rb +8 -0
  63. data/lib/myco/parser/ast/to_ruby/myco_module_scope.rb +8 -0
  64. data/lib/myco/parser/ast/to_ruby/null_literal.rb +6 -0
  65. data/lib/myco/parser/ast/to_ruby/parameters.rb +60 -0
  66. data/lib/myco/parser/ast/to_ruby/quest.rb +13 -0
  67. data/lib/myco/parser/ast/to_ruby/return.rb +7 -0
  68. data/lib/myco/parser/ast/to_ruby/scoped_constant.rb +11 -0
  69. data/lib/myco/parser/ast/to_ruby/self.rb +6 -0
  70. data/lib/myco/parser/ast/to_ruby/splat_value.rb +33 -0
  71. data/lib/myco/parser/ast/to_ruby/string_literal.rb +6 -0
  72. data/lib/myco/parser/ast/to_ruby/symbol_literal.rb +6 -0
  73. data/lib/myco/parser/ast/to_ruby/toplevel_constant.rb +11 -0
  74. data/lib/myco/parser/ast/to_ruby/true_literal.rb +6 -0
  75. data/lib/myco/parser/ast/to_ruby/void_literal.rb +6 -0
  76. data/lib/myco/parser/ast/to_ruby.rb +138 -0
  77. data/lib/myco/parser/ast.rb +6 -0
  78. data/lib/myco/parser/peg_parser.rb +361 -181
  79. data/lib/myco/parser.rb +27 -11
  80. data/lib/myco/tools/BasicCommand.my +42 -0
  81. data/lib/myco/tools/Generator.my +18 -0
  82. data/lib/myco/toolset.rb +0 -3
  83. data/lib/myco/version.rb +1 -4
  84. data/lib/myco.rb +2 -0
  85. metadata +230 -160
  86. data/lib/myco/parser/builder.output +0 -3995
  87. data/lib/myco/parser/builder.racc +0 -585
  88. data/lib/myco/parser/builder.rb +0 -1592
  89. data/lib/myco/parser/lexer.rb +0 -2306
  90. data/lib/myco/parser/lexer.rl +0 -393
  91. data/lib/myco/parser/lexer_char_classes.rl +0 -56
  92. data/lib/myco/parser/lexer_common.rb +0 -95
  93. data/lib/myco/parser/lexer_skeleton.rl +0 -154
  94. data/lib/myco/parser/peg_parser.kpeg +0 -759
  95. data/lib/myco/tools/OptionParser.my +0 -38
@@ -1,759 +0,0 @@
1
- %% name = CodeTools::PegParser
2
- #%
3
-
4
- %% { #%
5
- attr_accessor :processor
6
- attr_accessor :root_node
7
-
8
- # Generate an AST::Node of the given type (generated by the @processor)
9
- def node type, locator, *args
10
- @processor.send :"process_#{type}", locator.line, *args
11
- end
12
-
13
- # Generate a Token with the given type, text, and row_col
14
- def token type, text, row_col=nil
15
- row_col ||= [current_line, current_column-text.length]
16
- Token.new type, text, row_col
17
- end
18
-
19
- # A token is a lightweight unit of text with type and location info
20
- # as well as some convenience function for common conversion operations.
21
- class Token
22
- attr_accessor :type
23
- attr_accessor :text
24
- attr_accessor :line
25
-
26
- def inspect
27
- [@type, @text, @line].inspect
28
- end
29
- alias_method :to_s, :inspect
30
-
31
- def initialize type, text, row_col
32
- @type = type
33
- @text = text
34
- # TODO: integrate columns from location instead of just rows
35
- @line = row_col.first
36
- end
37
-
38
- def sym; @text.to_sym end
39
- def float; Float(@text) end
40
- def integer; Integer(@text) end
41
- end
42
- }
43
-
44
- ##
45
- # Things to remember about PEG:
46
- #
47
- # Given the choice (a | b | c),
48
- # PEG will consume the first matching choice, not the longest.
49
- # There is no ambiguity in PEG because all rule choices are order-dependent.
50
- # This means that you should avoid changing the order of choices
51
- # in a rule without being mindful of the consequences.
52
- #
53
- # Given a left-recursive set of rules such as
54
- # x = a | b | c
55
- # a = x "+" x
56
- # PEG will silently ignore the 'a' rule when trying to contruct 'x' and
57
- # not even try to pursue it because it would result in infinite recursion.
58
- # To avoid left-recursion while retaining left-associativity,
59
- # use an iteration rule instead of a recursion rule.
60
- # (see the chained_left_atoms rule)
61
-
62
-
63
- ##
64
- # Toplevel Terminal Categorizations
65
-
66
- root = declobj_expr_body:n0 { @root_node = node(:declfile, n0, n0) }
67
-
68
- # Declarations
69
- decl =
70
- declobj
71
- | declstr
72
- | copen
73
-
74
- # Expressions allowable inside object declarations
75
- declobj_expr =
76
- category
77
- | declobj_expr_not_category
78
-
79
- # Expressions allowable inside object declarations that is not a category
80
- declobj_expr_not_category =
81
- decl
82
- | cdefn
83
- | cmeme
84
- | constant
85
- | meme
86
-
87
- # Expressions allowable inside memes
88
- meme_expr =
89
- return_arg_expr
90
- | arg_expr
91
-
92
- # Expressions allowable as function arguments
93
- arg_expr =
94
- assignment
95
- | left_chained_atoms
96
- | dyn_string
97
- | dyn_symstr
98
- | expr_atom
99
-
100
- # TODO: make expr_atom not redundant with below rules
101
- # Expression atoms
102
- expr_atom =
103
- decl
104
- | left_chained_invocations
105
- | lit_string
106
- | lit_symstr
107
- | unary_operation
108
- | paren_expr
109
- | constant
110
- | lit_simple
111
- | lit_array
112
- | invoke
113
-
114
- # Expression atoms that are not invocation chains
115
- expr_atom_not_chained =
116
- decl
117
- | lit_string
118
- | lit_symstr
119
- | unary_operation
120
- | paren_expr
121
- | constant
122
- | lit_simple
123
- | lit_array
124
- | invoke
125
-
126
- # Expression atoms that are not strings
127
- expr_atom_not_string =
128
- decl
129
- | left_chained_invocations
130
- | unary_operation
131
- | paren_expr
132
- | constant
133
- | lit_simple
134
- | lit_array
135
- | invoke
136
-
137
-
138
- ##
139
- # Character Classes
140
-
141
- eol_comment = '#' (!c_eol .)*
142
-
143
- c_nl = "\n"
144
- c_spc = /[ \t\r\f\v]/ | "\\\n" | eol_comment
145
- c_spc_nl = c_spc | c_nl
146
-
147
- c_eof = !.
148
- c_eol = c_nl | c_eof
149
- c_any = .
150
-
151
- c_upper = /[[:upper:]]/
152
- c_lower = /[[:lower:]]/ | "_"
153
- c_num = /[0-9]/
154
- c_alpha = c_lower | c_upper
155
- c_alnum = c_alpha | c_num
156
- c_suffix = '!' | '?'
157
-
158
-
159
- ##
160
- # Tokens
161
-
162
- t_CONST_SEP = < ',' > ~token(:t_CONST_SEP, text)
163
- t_EXPR_SEP = < ';' | c_nl > ~token(:t_EXPR_SEP, text)
164
- t_ARG_SEP = < ',' | c_nl > ~token(:t_ARG_SEP, text)
165
- t_DECLARE_BEGIN = < '{' > ~token(:t_DECLARE_BEGIN, text)
166
- t_DECLARE_END = < '}' | c_eof > ~token(:t_DECLARE_END, text)
167
- t_MEME_MARK = < ':' > ~token(:t_MEME_MARK, text)
168
- t_MEME_BEGIN = < '{' > ~token(:t_MEME_BEGIN, text)
169
- t_MEME_END = < '}' > ~token(:t_MEME_END, text)
170
- t_PAREN_BEGIN = < '(' > ~token(:t_PAREN_BEGIN, text)
171
- t_PAREN_END = < ')' > ~token(:t_PAREN_END, text)
172
- t_DEFINE = < '<' > ~token(:t_DEFINE, text)
173
- t_REOPEN = < '<<' > ~token(:t_REOPEN, text)
174
- t_PARAMS_BEGIN = < '|' > ~token(:t_PARAMS_BEGIN, text)
175
- t_PARAMS_END = < '|' > ~token(:t_PARAMS_END, text)
176
- t_ARGS_BEGIN = < '(' > ~token(:t_ARGS_BEGIN, text)
177
- t_ARGS_END = < ')' > ~token(:t_ARGS_END, text)
178
- t_ARRAY_BEGIN = < '[' > ~token(:t_ARRAY_BEGIN, text)
179
- t_ARRAY_END = < ']' > ~token(:t_ARRAY_END, text)
180
-
181
- t_CONSTANT = < (c_upper c_alnum*) > ~token(:t_CONSTANT, text)
182
- t_IDENTIFIER = < (c_lower c_alnum*) c_suffix? >
183
- ~token(:t_IDENTIFIER, text)
184
- t_SYMBOL = ':' < (c_lower c_alnum*) > ~token(:t_SYMBOL, text)
185
-
186
- t_NULL = < 'null' > ~token(:t_NULL, text)
187
- t_VOID = < 'void' > ~token(:t_VOID, text)
188
- t_TRUE = < 'true' > ~token(:t_TRUE, text)
189
- t_FALSE = < 'false' > ~token(:t_FALSE, text)
190
- t_SELF = < 'self' > ~token(:t_SELF, text)
191
- t_FLOAT = < c_num+ '.' c_num+ > ~token(:t_FLOAT, text)
192
- t_INTEGER = < c_num+ > ~token(:t_INTEGER, text)
193
-
194
- t_JUMP = < '->' > ~token(:t_JUMP, text)
195
- t_DOT = < '.' > ~token(:t_DOT, text)
196
- t_QUEST = < '.' c_spc_nl* '?' > ~token(:t_QUEST, text)
197
- t_SCOPE = < '::' > ~token(:t_SCOPE, text)
198
- t_ASSIGN = < '=' > ~token(:t_ASSIGN, text)
199
- t_OP_TOPROC = < '&' > ~token(:t_OP_TOPROC, text)
200
- t_OP_NOT = < '!' > ~token(:t_OP_NOT, text)
201
- t_OP_PLUS = < '+' > ~token(:t_OP_PLUS, text)
202
- t_OP_MINUS = < '-' > ~token(:t_OP_MINUS, text)
203
- t_OP_MULT = < '*' > ~token(:t_OP_MULT, text)
204
- t_OP_DIV = < '/' > ~token(:t_OP_DIV, text)
205
- t_OP_MOD = < '%' > ~token(:t_OP_MOD, text)
206
- t_OP_EXP = < '**' > ~token(:t_OP_EXP, text)
207
- t_OP_AND = < '&&' > ~token(:t_OP_AND, text)
208
- t_OP_OR = < '||' > ~token(:t_OP_OR, text)
209
- t_OP_COMPARE = < ('<=>'|'=~'|'=='|'<='|'>='|'<'|'>') >
210
- ~token(:t_OP_COMPARE, text)
211
-
212
- string_norm = /[^\\\"]/
213
- t_STRING_BODY = < string_norm* ("\\" c_any string_norm*)* >
214
- ~token(:t_STRING_BODY, text)
215
- t_STRING_BEGIN = < '"' > ~token(:t_STRING_BEGIN, text)
216
- t_STRING_END = < '"' > ~token(:t_STRING_END, text)
217
- t_SYMSTR_BEGIN = < ':"' > ~token(:t_SYMSTR_BEGIN, text)
218
-
219
- sstring_norm = /[^\\\']/
220
- t_SSTRING_BODY = < sstring_norm* ("\\" c_any sstring_norm*)* >
221
- ~token(:t_SSTRING_BODY, text)
222
- t_SSTRING_BEGIN = < "'" > ~token(:t_SSTRING_BEGIN, text)
223
- t_SSTRING_END = < "'" > ~token(:t_SSTRING_END, text)
224
-
225
- catgry_norm = /[^\\\[\]]/
226
- t_CATGRY_BODY = < catgry_norm* ("\\" c_any catgry_norm*)* >
227
- ~token(:t_CATGRY_BODY, text)
228
- t_CATGRY_BEGIN = < '[' > ~token(:t_CATGRY_BEGIN, text)
229
- t_CATGRY_END = < ']' > ~token(:t_CATGRY_END, text)
230
-
231
-
232
- ##
233
- # Simple literals
234
-
235
- lit_simple =
236
- t_NULL:t0 ~node(:null, t0)
237
- | t_VOID:t0 ~node(:void, t0)
238
- | t_TRUE:t0 ~node(:true, t0)
239
- | t_FALSE:t0 ~node(:false, t0)
240
- | t_SELF:t0 ~node(:self, t0)
241
- | t_FLOAT:t0 ~node(:lit, t0, t0.float)
242
- | t_INTEGER:t0 ~node(:lit, t0, t0.integer)
243
- | t_SYMBOL:t0 ~node(:lit, t0, t0.sym)
244
-
245
- ##
246
- # Enclosed literals
247
-
248
- lit_string =
249
- t_STRING_BEGIN t_STRING_BODY:tb t_STRING_END
250
- ~node(:lit, tb, encode_escapes(tb.text))
251
- | t_SSTRING_BEGIN t_SSTRING_BODY:tb t_SSTRING_END
252
- ~node(:lit, tb, encode_escapes(tb.text))
253
-
254
- lit_string_as_symbol = # Used in contexts where a bare string is a symbol
255
- t_STRING_BEGIN t_STRING_BODY:tb t_STRING_END
256
- ~node(:lit, tb, encode_escapes(tb.text).to_sym)
257
- | t_SSTRING_BEGIN t_SSTRING_BODY:tb t_SSTRING_END
258
- ~node(:lit, tb, encode_escapes(tb.text).to_sym)
259
-
260
- lit_symstr =
261
- t_SYMSTR_BEGIN t_STRING_BODY:tb t_STRING_END
262
- ~node(:lit, tb, encode_escapes(tb.text).to_sym)
263
-
264
- category_name = # Used only in declobj body
265
- t_CATGRY_BEGIN t_CATGRY_BODY:tb t_CATGRY_END
266
- ~node(:lit, tb, encode_escapes(tb.text).to_sym)
267
-
268
- ##
269
- # String interpolations / juxtapositions
270
-
271
- expr_atom_evstr =
272
- expr_atom_not_string:n0
273
- ~node(:evstr, n0, n0)
274
-
275
- dyn_string_parts =
276
- (c_spc* expr_atom_evstr:n0 c_spc* lit_string:n1 {[n0,n1]})+:nlist
277
- { nlist.flatten }
278
-
279
- dyn_string =
280
- lit_string:n0 dyn_string_parts:nrest
281
- ~node(:dstr, n0, n0.value, nrest)
282
-
283
- dyn_symstr =
284
- lit_symstr:n0 dyn_string_parts:nrest
285
- ~node(:dsym, n0, n0.value.to_s, nrest)
286
-
287
- ##
288
- # Constants
289
-
290
- constant =
291
- constant:n0 t_SCOPE:ts t_CONSTANT:tc ~node(:colon2, ts, n0, tc.sym)
292
- | t_SCOPE:ts t_CONSTANT:tc ~node(:colon3, ts, tc.sym)
293
- | t_CONSTANT:tc ~node(:const, tc, tc.sym)
294
-
295
- const_sep = (c_spc_nl* t_CONST_SEP c_spc_nl*)+
296
-
297
- constant_list =
298
- constant:n0 (const_sep constant:n)*:nrest
299
- ~node(:array, n0, [n0, *nrest])
300
-
301
- ##
302
- # Bare identifiers
303
-
304
- # Used in contexts where a bare identifier is a symbol
305
- id_as_symbol = t_IDENTIFIER:t0 ~node(:lit, t0, t0.sym)
306
-
307
- ##
308
- # Object declarations
309
-
310
- declobj_sepd_exprs =
311
- declobj_expr:n0 (arg_sep declobj_expr:n)*:nrest arg_sep_opt { [n0, *nrest] }
312
-
313
- declobj_expr_body =
314
- arg_sep_opt declobj_sepd_exprs:nlist t_DECLARE_END:te
315
- ~node(:block, nlist.first, nlist)
316
- | arg_sep_opt t_DECLARE_END:te
317
- ~node(:null, te)
318
-
319
- declobj =
320
- constant_list:n0 c_spc_nl* t_DECLARE_BEGIN:t declobj_expr_body:n1
321
- ~node(:declobj, t, n0, n1)
322
-
323
- category_expr =
324
- declobj_expr_not_category
325
-
326
- category_sepd_exprs =
327
- category_expr:n0 (arg_sep category_expr:n)*:nrest { [n0, *nrest] }
328
-
329
- category =
330
- category_name:n0 arg_sep category_sepd_exprs?:nlist &(arg_sep_opt (t_CATGRY_BEGIN | t_DECLARE_END))
331
- ~node(:category, n0, n0,
332
- (nlist ? node(:block, nlist.first, nlist) : node(:null, n0)))
333
-
334
- copen =
335
- constant:n0 c_spc_nl* t_REOPEN:tb c_spc_nl* t_DECLARE_BEGIN declobj_expr_body:n1
336
- ~node(:copen, tb, n0, n1)
337
-
338
- cdefn =
339
- constant:n0 c_spc_nl* t_DEFINE:t c_spc_nl* declobj:n1
340
- ~node(:cdefn, t, n0, n1)
341
-
342
- ##
343
- # String object declarations
344
-
345
- t_DECLSTR_BEGIN =
346
- < /[^\s{:,<][^\s]+/ >
347
- {
348
-
349
- # Table of replacement characters to use when calculating
350
- # the ending delimiter from the starting delimiter.
351
- # Directional characters are replaced with their opposite.
352
- @declstr_replace_tbl ||= %w{
353
- < > ( ) { } [ ]
354
- }
355
-
356
- # Calculate the ending delimiter to look for and store it
357
- @declstr_destrlim = text \
358
- .split(/(?<=[^a-zA-Z])|(?=[^a-zA-Z])/)
359
- .map { |str|
360
- idx = @declstr_replace_tbl.find_index(str)
361
- idx.nil? ? str :
362
- (idx.odd? ? @declstr_replace_tbl[idx-1] : @declstr_replace_tbl[idx+1])
363
- }
364
- .reverse
365
- .join ''
366
-
367
- token(:t_DECLSTR_BEGIN, text)
368
- }
369
-
370
- t_DECLSTR_END =
371
- c_spc_nl* < (< /\S+/ > &{text == @declstr_destrlim}) >
372
- ~token(:t_DECLSTR_END, text)
373
-
374
- s_DECLSTR_BODYLINE =
375
- < /[^\n]*\n/ >
376
- &{ text =~ /^(\s*)(\S+)/; $2!=@declstr_destrlim }
377
- { text }
378
-
379
- s_DECLSTR_BODY =
380
- s_DECLSTR_BODYLINE*:slist
381
- { slist[1..-1].join('') }
382
-
383
- declstr_body =
384
- t_DECLSTR_BEGIN:tb s_DECLSTR_BODY:st c_spc_nl* t_DECLSTR_END
385
- ~node(:str, tb, st)
386
-
387
- declstr =
388
- constant_list:nc c_spc+ declstr_body:nb
389
- ~node(:declstr, nc, nc, nb)
390
-
391
- ##
392
- # Jumps
393
-
394
- return_arg_expr =
395
- arg_expr:n0 c_spc* t_JUMP:to
396
- ~node(:return, to, n0)
397
-
398
- ##
399
- # Assignment
400
-
401
- assignment =
402
- local_assignment
403
- | invoke_assignment
404
-
405
- assign_rhs =
406
- arg_expr
407
-
408
- local_assignment =
409
- t_IDENTIFIER:ti c_spc_nl* t_ASSIGN:to c_spc_nl* assign_rhs:rhs
410
- ~node(:lasgn, to, ti.sym, rhs)
411
-
412
- invoke_assignment_lhs =
413
- left_chained_invocations
414
- | invoke
415
-
416
- invoke_assignment =
417
- invoke_assignment_lhs:lhs c_spc_nl* t_ASSIGN:to c_spc_nl* assign_rhs:rhs
418
- {
419
- lhs.name = :"#{lhs.name}="
420
- orig_arguments = lhs.arguments && lhs.arguments.body || []
421
- lhs.arguments = node(:array, rhs, [rhs, *orig_arguments])
422
- lhs
423
- }
424
-
425
-
426
- ##
427
- # Invoke - Results in a :lambig, :call, or :iter with a :call within
428
-
429
- invoke_body =
430
- (c_spc_nl* param_list:n)?:np c_spc_nl* meme_enclosed_expr_body:nb
431
- { [np, nb] }
432
-
433
- invoke =
434
- t_IDENTIFIER:tn (c_spc_nl* arg_list:na)?:na (c_spc_nl* invoke_body:n)?:nlist
435
- ~node(:invoke, tn, nil, tn.sym, na, *nlist)
436
-
437
- op_invoke = # Allow some binary operators to be invoked with a dot
438
- op_invoke_id:tn (c_spc_nl* arg_list:na)?:na (c_spc_nl* invoke_body:n)?:nlist
439
- ~node(:invoke, tn, nil, tn.sym, na, *nlist)
440
-
441
- op_invoke_id =
442
- left_op
443
-
444
- ##
445
- # Argument lists
446
-
447
- arg_sep = (c_spc* t_ARG_SEP c_spc*)+
448
- arg_sep_opt = (c_spc | t_ARG_SEP)*
449
-
450
- in_arg_normal =
451
- in_arg_splat
452
- | arg_expr:n0 !in_arg_kwarg_mark { n0 }
453
-
454
- in_arg_normals =
455
- in_arg_normal:n0 (arg_sep in_arg_normal:n)*:nrest
456
- { [n0,*nrest] }
457
-
458
- in_arg_kwargs =
459
- in_arg_kwarg:n0 (arg_sep in_arg_kwarg:n)*:nrest
460
- ~node(:hash, n0.first, [n0,*nrest].flatten)
461
-
462
- in_arg_kwarg_mark = c_spc_nl* t_MEME_MARK:to
463
- in_arg_kwarg =
464
- id_as_symbol:n0 in_arg_kwarg_mark c_spc_nl* arg_expr:n1
465
- { [n0, n1] }
466
-
467
- in_arg_splat =
468
- t_OP_MULT:to expr_atom:n0
469
- ~node(:splat, to, n0)
470
-
471
- in_arg_block =
472
- t_OP_TOPROC:to expr_atom:n0
473
- ~node(:block_pass, to, nil, n0)
474
-
475
- in_arg_list =
476
- in_arg_normals:n0 arg_sep in_arg_kwargs:n1 arg_sep in_arg_block:n2 { [*n0,n1,n2] }
477
- | in_arg_normals:n0 arg_sep in_arg_kwargs:n1 { [*n0,n1] }
478
- | in_arg_normals:n0 arg_sep in_arg_block:n1 { [*n0,n1] }
479
- | in_arg_kwargs:n0 arg_sep in_arg_block:n1 { [n0, n1] }
480
- | in_arg_normals:n0 { [*n0] }
481
- | in_arg_kwargs:n0 { [n0] }
482
- | in_arg_block:n0 { [n0] }
483
-
484
- arg_list =
485
- t_ARGS_BEGIN:tb arg_sep_opt t_ARGS_END
486
- ~args_assemble(tb, node(:array, tb, []))
487
- | t_ARGS_BEGIN:tb arg_sep_opt in_arg_list:nlist arg_sep_opt t_ARGS_END
488
- ~args_assemble(tb, node(:array, tb, nlist))
489
-
490
- lit_array =
491
- t_ARRAY_BEGIN:tb arg_sep_opt t_ARRAY_END
492
- ~args_assemble(tb, node(:array, tb, []))
493
- | t_ARRAY_BEGIN:tb arg_sep_opt in_arg_list:nlist arg_sep_opt t_ARRAY_END
494
- ~args_assemble(tb, node(:array, tb, nlist))
495
-
496
- ##
497
- # Parameter lists
498
-
499
- param =
500
- t_IDENTIFIER:ti c_spc_nl* t_ASSIGN:to c_spc_nl* arg_expr:nv
501
- { [:optional, node(:lasgn, ti, ti.sym, nv)] }
502
- | t_IDENTIFIER:ti c_spc_nl* t_MEME_MARK:to c_spc_nl* arg_expr?:nv
503
- { [:kwargs, node(:lasgn, ti, ti.sym, (nv || node(:lit, to, :*)))] }
504
- | t_OP_EXP c_spc_nl* t_IDENTIFIER:ti { [:kwrest, ti.sym] }
505
- | t_OP_MULT c_spc_nl* t_IDENTIFIER:ti { [:rest, ti.sym] }
506
- | t_OP_TOPROC c_spc_nl* t_IDENTIFIER:ti { [:block, ti.sym] }
507
- | t_IDENTIFIER:ti { [:required, ti.sym] }
508
-
509
- param_sepd =
510
- arg_sep param:n0 { n0 }
511
-
512
- param_sepds =
513
- param:n0 (arg_sep param:n)*:nrest arg_sep_opt { [n0, *nrest] }
514
-
515
- param_list =
516
- t_PARAMS_BEGIN:tb t_PARAMS_END
517
- { node(:args, tb, nil, nil, nil, nil, nil, nil, nil) }
518
- | t_PARAMS_BEGIN:tb param_sepds:plist t_PARAMS_END
519
- {
520
- required, optional, rest, kwargs, kwrest, block = 6.times.map { [] }
521
-
522
- required << plist.shift[1] while plist[0] && plist[0][0] == :required
523
- optional << plist.shift[1] while plist[0] && plist[0][0] == :optional
524
- rest << plist.shift[1] while plist[0] && plist[0][0] == :rest
525
- kwargs << plist.shift[1] while plist[0] && plist[0][0] == :kwargs
526
- kwrest << plist.shift[1] while plist[0] && plist[0][0] == :kwrest
527
- block << plist.shift[1] while plist[0] && plist[0][0] == :block
528
-
529
- required = required
530
- optional = optional.empty? ? nil : node(:block, tb, optional)
531
- rest = rest.first
532
- post = nil
533
- kwargs = kwargs.empty? ? nil : node(:block, tb, kwargs)
534
- kwrest = kwrest.first
535
- block = block.first
536
-
537
- node(:args, tb, required, optional, rest, post, kwargs, kwrest, block)
538
- }
539
-
540
- ##
541
- # Two-term operators
542
-
543
- left_op =
544
- t_OP_EXP
545
- | t_OP_MULT | t_OP_DIV | t_OP_MOD
546
- | t_OP_PLUS | t_OP_MINUS
547
- | t_OP_COMPARE
548
- | t_OP_AND | t_OP_OR
549
-
550
- # Achieve left-associativity through iteration.
551
- #
552
- # PEG parsers get tripped up by left recursion
553
- # (in contrast to LALR parsers, which prefer left recursion).
554
- # This is a well-understood limitation, but refer to:
555
- # http://www.dalnefre.com/wp/2011/05/parsing-expression-grammars-part-4/
556
- # for an easy-to-understand explanation of this problem and this solution.
557
- #
558
- left_chained_atoms =
559
- expr_atom:n0 (c_spc_nl* left_op:to c_spc_nl* expr_atom:n1 { [to, n1] })+:list
560
- {
561
- list.unshift n0
562
- list.flatten!
563
-
564
- collapse(list, :t_OP_EXP)
565
- collapse(list, :t_OP_MULT, :t_OP_DIV, :t_OP_MOD)
566
- collapse(list, :t_OP_PLUS, :t_OP_MINUS)
567
- collapse(list, :t_OP_COMPARE)
568
- collapse(list, :t_OP_AND, :t_OP_OR) do |n0,op,n1|
569
- type = { :t_OP_AND=>:and, :t_OP_OR=>:or }[op.type]
570
- node(type, op, n0, n1)
571
- end
572
-
573
- # There should only be one resulting node left
574
- raise "Failed to fully collapse left_chained_atoms: #{list}" \
575
- unless list.count == 1
576
-
577
- list.first
578
- }
579
-
580
- ##
581
- # Invocations and Quests (soft-failing invocations)
582
-
583
- left_invoke_op =
584
- t_QUEST
585
- | t_DOT
586
-
587
- # Achieve left-associativity through iteration.
588
- # (see left_chained_atoms).
589
- #
590
- left_chained_invocations =
591
- expr_atom_not_chained:n0 (c_spc_nl* left_invoke_op:to c_spc_nl* (invoke | op_invoke):n1 { [to, n1] })+:list
592
- {
593
- list.unshift n0
594
- list.flatten!
595
-
596
- collapse(list, :t_DOT, :t_QUEST) do |n0,op,n1|
597
- op.type==:t_DOT ? (n1.receiver=n0; n1) : node(:quest, op, n0, n1)
598
- end
599
-
600
- # There should only be one resulting node left
601
- raise "Failed to fully collapse left_chained_invocations: #{list}" \
602
- unless list.count == 1
603
-
604
- list.first
605
- }
606
-
607
- ##
608
- # Unary operators
609
-
610
- unary_operation =
611
- t_OP_NOT:to expr_atom:n0
612
- ~node(:call, to, n0, :"!", nil)
613
-
614
- ##
615
- # Memes and etc..
616
-
617
- t_inln_sep = !t_ARG_SEP t_EXPR_SEP
618
-
619
- inln_sep = (c_spc* t_inln_sep c_spc*)+
620
- inln_sep_opt = (c_spc | t_inln_sep)*
621
-
622
- expr_sep = (c_spc* t_EXPR_SEP c_spc*)+
623
- expr_sep_opt = (c_spc | t_EXPR_SEP)*
624
-
625
- meme_inline_sepd_exprs =
626
- meme_expr:n0 (inln_sep meme_expr:n)*:nrest inln_sep_opt { [n0, *nrest] }
627
-
628
- meme_sepd_exprs =
629
- meme_expr:n0 (expr_sep meme_expr:n)*:nrest expr_sep_opt { [n0, *nrest] }
630
-
631
- meme_inline_expr_body =
632
- inln_sep_opt meme_inline_sepd_exprs:nlist
633
- ~node(:block, nlist.first, nlist)
634
-
635
- meme_expr_body =
636
- expr_sep_opt meme_sepd_exprs:nlist t_MEME_END:te
637
- ~node(:block, nlist.first, nlist)
638
- | expr_sep_opt t_MEME_END:te
639
- ~node(:null, te)
640
-
641
- paren_expr_body =
642
- expr_sep_opt meme_sepd_exprs:nlist t_PAREN_END:te
643
- { nlist.count==1 ? nlist.first : node(:block, nlist.first, nlist) }
644
- | expr_sep_opt t_PAREN_END:te
645
- ~node(:null, te)
646
-
647
- paren_expr =
648
- t_PAREN_BEGIN paren_expr_body:n0 { n0 }
649
-
650
- meme_enclosed_expr_body =
651
- t_MEME_BEGIN meme_expr_body:n0 { n0 }
652
-
653
- meme_either_body =
654
- meme_enclosed_expr_body
655
- | meme_inline_expr_body
656
-
657
- cmeme =
658
- constant:n0 c_spc* t_MEME_MARK:tm c_spc_nl* meme_inline_expr_body:n1
659
- ~node(:cdecl, tm, n0, n1)
660
-
661
- meme_name =
662
- id_as_symbol
663
- | lit_string_as_symbol
664
-
665
- decorator =
666
- meme_name:ni arg_list?:na
667
- ~node(:deco, ni, ni, na)
668
-
669
- decorators_and_meme_name =
670
- decorator:n0 (c_spc* decorator:n)*:nrest
671
- ~node(:array, n0, [n0, *nrest].reverse)
672
-
673
- meme =
674
- decorators_and_meme_name:nd c_spc* t_MEME_MARK:tm (c_spc_nl* param_list:n)?:np c_spc_nl* meme_either_body:nb
675
- ~node(:meme, tm, nd.body.shift.name, nd, np, nb)
676
- | decorators_and_meme_name:nd
677
- ~node(:meme, tm, nd.body.shift.name, nd, nil, nil)
678
-
679
-
680
- %% {
681
- #%
682
- # Encode escape characters in string literals
683
- # TODO: rigorously test and refine
684
- #
685
- def encode_escapes str
686
- str.gsub /\\(.)/ do "#{$1}" end
687
- end
688
-
689
- # Given a node,op list ([node, op, node, op, ... node]) and operator types,
690
- # collapse the (node, op, node) groups where the operator is one of the types
691
- #
692
- # This function is meant to be called several times on the same list,
693
- # with a different set of operator types each time, in order of precedence.
694
- #
695
- def collapse input, *types
696
- output = []
697
-
698
- # Scan through, reducing or shifting based on the operator
699
- while input.count > 2
700
- n0 = input.shift
701
- op = input.shift
702
-
703
- if types.include? op.type
704
- n1 = input.shift
705
-
706
- result = block_given? ?
707
- yield(n0,op,n1) :
708
- node(:call, op, n0, op.sym, node(:array, n1, [n1]))
709
- input.unshift result
710
- else
711
- output.push n0
712
- output.push op
713
- end
714
- end
715
-
716
- # Push the last item remaining
717
- output.push input.shift
718
-
719
- input.replace output
720
- end
721
-
722
- # Given a locator and an node(:array), refactor the splat-related nodes
723
- # in a copy of the original node body and return a replacement for the node.
724
- #
725
- def args_assemble loc, orig_node
726
- list = orig_node.body.dup
727
- tmp = []
728
-
729
- special_type_check = Proc.new { |x|
730
- case x
731
- when Myco::ToolSet::AST::SplatValue; :splat
732
- when Myco::ToolSet::AST::ConcatArgs; :argscat
733
- when Myco::ToolSet::AST::PushArgs; :argspush
734
- when Myco::ToolSet::AST::BlockPass; :block_pass
735
- else; nil
736
- end
737
- }
738
-
739
- # Get the original value in the new_node
740
- tmp << list.shift until list.empty? or special_type_check.call(list.first)
741
- new_node = tmp.empty? ? list.shift : node(:array, loc, tmp)
742
-
743
- # Continue to reduce until all elements have been used
744
- until list.empty?
745
- arg = list.shift
746
- type = special_type_check.call(arg)
747
- if type == :block_pass
748
- new_node = arg.tap { |n| n.arguments = new_node }
749
- elsif type != nil
750
- new_node = node(:argscat, loc, new_node, arg)
751
- else
752
- new_node = node(:argspush, loc, new_node, arg)
753
- end
754
- end
755
-
756
- new_node || orig_node
757
- end
758
-
759
- }