rubymacros 0.1.5 → 0.1.6

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 (63) hide show
  1. checksums.yaml +4 -0
  2. data/COPYING.LGPL +503 -158
  3. data/History.txt +115 -5
  4. data/Makefile +68 -0
  5. data/README.txt +29 -6
  6. data/TODO +1 -0
  7. data/bin/macroruby +69 -0
  8. data/example/__dir__.rb +18 -0
  9. data/example/__dir___wrap.rb +18 -0
  10. data/example/andand.rb +18 -0
  11. data/example/andand_wrap.rb +18 -0
  12. data/example/assert.rb +29 -8
  13. data/example/assert0.rb +11 -0
  14. data/example/assert0_wrap.rb +5 -0
  15. data/example/assert_does_nothing_when_disabled.rb +19 -0
  16. data/example/assert_wrap.rb +21 -0
  17. data/example/expected_output.txt +88 -0
  18. data/example/formless_macro.rb +123 -0
  19. data/example/formless_macro_wrap.rb +20 -0
  20. data/example/inline.rb +97 -0
  21. data/example/linenum.rb +19 -1
  22. data/example/linenum_user.rb +18 -0
  23. data/example/linenum_wrap.rb +18 -0
  24. data/example/loop.rb +18 -0
  25. data/example/loop_wrap.rb +18 -0
  26. data/example/meta.rb +25 -0
  27. data/example/meta_wrap.rb +20 -0
  28. data/example/nilresult.rb +26 -0
  29. data/example/nilresult_wrap.rb +21 -0
  30. data/example/pipeline.rb +37 -0
  31. data/example/rescuing.rb +33 -0
  32. data/example/rescuing_wrap.rb +21 -0
  33. data/example/role.rb +103 -0
  34. data/example/role_with_eval.rb +92 -0
  35. data/example/self_in_class.rb +27 -0
  36. data/example/separated_scope.rb +42 -0
  37. data/example/separated_scope_wrap.rb +20 -0
  38. data/example/simple.rb +18 -0
  39. data/example/simple_wrap.rb +18 -0
  40. data/example/unproc.rb +31 -0
  41. data/example/unproc_wrap.rb +21 -0
  42. data/example/unroll.rb +34 -0
  43. data/example/unroll_macros.rb +119 -0
  44. data/example/unroll_wrap.rb +22 -0
  45. data/example/with.rb +50 -7
  46. data/example/with_wrap.rb +19 -0
  47. data/lib/macro.rb +307 -72
  48. data/lib/macro/ReduceWithsFor_RedParse_RedParse__MacroMixin_RedParse__WithMacros_1_8.rb +18880 -0
  49. data/lib/macro/ReduceWithsFor_RedParse_RedParse__MacroMixin_RedParse__WithMacros_1_9.rb +19101 -0
  50. data/lib/macro/form.rb +136 -27
  51. data/lib/macro/node.rb +64 -0
  52. data/lib/macro/version.rb +2 -5
  53. data/lib/rubymacros.rb +19 -0
  54. data/lib/rubymacros/version.rb +23 -0
  55. data/lib/weakkeyhash.rb +18 -0
  56. data/rubymacros.gemspec +60 -0
  57. data/test/test_all.rb +27 -2
  58. data/test/test_examples.rb +91 -0
  59. data/test/test_expand.rb +56 -1
  60. data/test/test_form.rb +108 -10
  61. data/test/test_unroll.rb +120 -0
  62. metadata +93 -65
  63. data/Rakefile +0 -37
@@ -1,6 +1,6 @@
1
1
  =begin
2
2
  rubymacros - a macro preprocessor for ruby
3
- Copyright (C) 2008 Caleb Clausen
3
+ Copyright (C) 2008, 2016 Caleb Clausen
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify
6
6
  it under the terms of the GNU Lesser General Public License as published by
@@ -20,11 +20,13 @@
20
20
  #$: << "../redparse/lib"
21
21
 
22
22
  require "redparse"
23
- require "macro"
23
+ #require "macro"
24
24
  class Macro
25
25
  # The syntax node for forms
26
26
  class FormNode < RedParse::ValueNode
27
27
  param_names :text
28
+ alias val text
29
+ alias body text
28
30
 
29
31
  # Create a new form node. The user should normally not call this
30
32
  # function. Form nodes are created by the parser.
@@ -33,21 +35,66 @@ class Macro
33
35
  # +text+:: A ParenedNode or VarLikeNode
34
36
  #
35
37
  def initialize(colon,text)
38
+ @startline=@endline=nil
39
+
36
40
  # Certain node types need to be quoted
37
- if RedParse::VarLikeNode===text
41
+ # (or rather, not unquoted)
42
+ if RedParse::VarLikeNode===text
43
+ #this code is dead now, I believe
38
44
  @transform=HashLiteralNode[]
45
+ @stars_transform=HashLiteralNode[]
46
+ text.startline=text.endline=0
39
47
  super text
40
48
  return
41
49
  end
42
50
 
51
+
43
52
  # Sanity check - make sure this is a valid ParenedNode
44
- fail unless ParenedNode===text && text.size==1
45
- text=text.body
53
+ if ParenedNode===text && text.size==1
54
+ text=text.body #unquote the form
55
+ elsif text.size==0
56
+ @transform=HashLiteralNode[]
57
+ @stars_transform=HashLiteralNode[]
58
+ super SequenceNode[]
59
+ return
60
+ end
46
61
 
47
62
  super text
48
63
  rebuild_transform
49
64
  end
50
65
 
66
+ def noinspect_instance_variables
67
+ %w[@stars_transform @transform]
68
+ end
69
+
70
+ def initialize_copy other
71
+ replace other
72
+ other.instance_variables{|v|
73
+ instance_variable_set v, other.instance_variable_get(v)
74
+ }
75
+ rebuild_transform
76
+ end
77
+
78
+ def _dump depth
79
+ Marshal.dump text,depth
80
+ end
81
+
82
+ def self._load str
83
+ result=allocate
84
+ result.replace [Marshal.load(str)]
85
+ result.rebuild_transform
86
+ end
87
+
88
+ =begin fake _dump/_load, for testing purposes
89
+ def _dump depth
90
+ "foobarbaz"
91
+ end
92
+
93
+ def self._load str
94
+ result=allocate
95
+ end
96
+ =end
97
+
51
98
  def initialize_ivars
52
99
  rebuild_transform
53
100
  super
@@ -58,15 +105,17 @@ class Macro
58
105
  def rebuild_transform
59
106
  # TODO: this method needs to be better documented/refactored
60
107
  @transform=HashLiteralNode[]
108
+ @stars_transform=HashLiteralNode[]
61
109
  @parameters=[]
110
+ @parameters.extend RedParse::ListInNode
62
111
 
63
112
  walkers=proc{|rcvr,wraplayers| #curry
64
- rcvr.walk{|*args|
65
- node=args.last
113
+ rcvr.walk{|parent,i,j,node|
114
+ node.startline=node.endline=0 if node.respond_to? :startline
66
115
  case node
67
- when FormParameterNode
116
+ when FormEscapeNode
68
117
  target=node.wraplevel
69
- fail if wraplayers > target
118
+ #fail if wraplayers > target
70
119
  if wraplayers==target #skip this parameter if it doesn't have enough wrappers
71
120
  @parameters << node #remember parameter (and implicitly, location)
72
121
 
@@ -87,9 +136,13 @@ class Macro
87
136
 
88
137
  @parameters.each{|orig_escd|
89
138
  escd=orig_escd
90
- escd=escd.val while FormParameterNode===escd
91
- @transform.push LiteralNode[orig_escd.__id__], escd
92
- }
139
+ escd=escd.val while FormEscapeNode===escd
140
+ if UnaryStarNode===escd
141
+ @stars_transform.push LiteralNode[orig_escd.__id__], escd.val
142
+ else
143
+ @transform.push LiteralNode[orig_escd.__id__], escd
144
+ end
145
+ }
93
146
 
94
147
  return self
95
148
  end
@@ -99,7 +152,7 @@ class Macro
99
152
  # +block+:: the block to call for each parameter
100
153
  #
101
154
  def each_parameter(&block)
102
- @parameters.each(&block) if @parameters
155
+ @parameters.each(&block) if defined? @parameters
103
156
  end
104
157
 
105
158
  # Make a deep copy of this form
@@ -125,7 +178,9 @@ class Macro
125
178
  #
126
179
  # +transform+:: the transform to use in the deep copy
127
180
  #
128
- def reify transform
181
+ def reify transform, stars_transform
182
+ transform&&=transform.dup
183
+ stars_transform&&=stars_transform.dup
129
184
  transform.each_pair{|k,v|
130
185
  case v
131
186
  when Node; next
@@ -134,7 +189,32 @@ class Macro
134
189
  end
135
190
  transform[k]=v
136
191
  }
137
- deep_copy(transform)
192
+ stars_transform.each_pair{|k,v|
193
+ case v
194
+ when Symbol; v=CallNode[nil,v.to_s]
195
+ else v=Macro.quote v
196
+ end
197
+ stars_transform[k]=v.extend InlineList
198
+ }
199
+ result=deep_copy(transform.merge( stars_transform ))
200
+ #expand InlineLists somehow
201
+ result.walk{|parent,i,j,node|
202
+ if InlineList===node
203
+ if j
204
+ parent[i][j,1]=*node
205
+ else
206
+ parent[i,1]=*node
207
+ end
208
+ nil #halt further recursion
209
+ else
210
+ true
211
+ end
212
+ } unless stars_transform.empty?
213
+
214
+ return result
215
+ end
216
+
217
+ module InlineList
138
218
  end
139
219
 
140
220
  # Transform this node into a ParseTree parse tree
@@ -171,27 +251,55 @@ class Macro
171
251
  # RedParse::SomeNodeType[ some transform of code ]
172
252
  #
173
253
  def parses_like
174
- CallSiteNode[CallSiteNode[formname, "reify", [@transform]], "text"]
175
- #:(^(formname).reify(^@transform).text)
254
+ startline=@startline if defined? @startline
255
+ endline=@endline if defined? @endline
256
+ ivars={:@startline=>startline, :@endline=>endline}
257
+ CallSiteNode[
258
+ CallSiteNode[formname, "reify", [@transform,@stars_transform], ivars],
259
+ "text", ivars
260
+ ]
261
+ #:(^(formname).reify(^@transform,^@stars_transform).text)
176
262
  end
177
263
 
178
264
  # Lazily evaluate the name of the form and return it
179
265
  def formname
180
- @formname ||= ConstantNode[nil,"Macro","Names",::Macro::Names.request(self)]
266
+ startline=@startline if defined? @startline
267
+ endline=@endline if defined? @endline
268
+ ivars={:@startline=>startline, :@endline=>endline}
269
+
270
+ @formname ||= ConstantNode[nil,"Macro","Names",::Macro::Names.request(self), ivars]
181
271
  end
182
272
  end
183
273
 
184
274
 
185
275
  # The syntax node for a form escape
186
- class FormParameterNode < RedParse::ValueNode
276
+ class FormEscapeNode < RedParse::ValueNode
187
277
  param_names :val
278
+ alias body val
188
279
 
280
+ =begin not needed now?
281
+ def initialize(*args)
282
+ super(args.last)
283
+ end
284
+ =end
189
285
  # Called by the parser to create a new form parameter node.
190
286
  #
191
- # +args+:: TODO
287
+ # +args+:: the ^ token (unused), and its argument
192
288
  #
193
- def initialize(*args)
194
- super(args.last)
289
+
290
+
291
+ def self.create(*args)
292
+ v=args.last
293
+ case v
294
+ when UndefNode; v=MisparsedNode.new('',v,'')
295
+ when KeywordToken
296
+ case v.ident
297
+ when /\A(?:;|\+>)\z/; v=args[-2]
298
+ when ')'; huh "v foo;(*params) unhandled yet"
299
+ else fail
300
+ end
301
+ end
302
+ new v
195
303
  end
196
304
 
197
305
  # Performs the reverse of a parse operation (turns the node into a
@@ -203,15 +311,16 @@ class Macro
203
311
  "^"+val.unparse(o)
204
312
  end
205
313
 
314
+ def lhs_unparse o=default_unparse_options
315
+ "(^"+val.unparse(o)+")"
316
+ end
317
+
206
318
  # The number of carats (^) that occur in the escape. Note that
207
319
  # this method is recursive.
208
320
  def wraplevel
209
- return val.wraplevel+1 if FormParameterNode===val
321
+ return val.wraplevel+1 if FormEscapeNode===val
210
322
  return 1
211
323
  end
212
-
213
- def inspect
214
- val.unparse
215
- end
216
324
  end
325
+ FormParameterNode=FormEscapeNode
217
326
  end
@@ -0,0 +1,64 @@
1
+ =begin
2
+ rubymacros - a macro preprocessor for ruby
3
+ Copyright (C) 2008, 2016 Caleb Clausen
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+ class RedParse
20
+ class Node
21
+ def replace_flow_control(replacer)
22
+ fail "retry is hard! & changes semantics in ruby 1.9" if replacer[:retry]
23
+ return_yield={}
24
+ return_yield[:return]=replacer[:return] if replacer[:return]
25
+ return_yield[:yield]=replacer[:yield] if replacer[:yield]
26
+ walk{|parent,i,j,node|
27
+ case node
28
+ when KWCallNode
29
+ if action=replacer[node.name.to_sym]
30
+ newnode=action[*node.params]
31
+ if j
32
+ parent[i][j]=newnode
33
+ else
34
+ parent[i]=newnode
35
+ end
36
+ end
37
+ true
38
+ when LoopNode, UntilOpNode, WhileOpNode
39
+ #nested loops hide break/next/redo
40
+ node.condition.replace_flow_control(replacer)
41
+ node.body.replace_flow_control(return_yield) if node.body and !return_yield.empty?
42
+ false
43
+ when MethodNode,ClassNode,ModuleNode,MetaClassNode
44
+ node.receiver.replace_flow_control(replacer) if node.receiver
45
+ #but not in body, rescues, else, ensure
46
+ false
47
+ when CallNode
48
+ node.receiver.replace_flow_control(replacer) if node.receiver
49
+ node.params.each{|param| param.replace_flow_control(replacer) } if node.params
50
+ #but only return/yield in block or blockparams
51
+ unless return_yield.empty?
52
+ node.blockparams.each{|bparam| bparam.replace_flow_control(return_yield) } if node.blockparams
53
+ node.block.replace_flow_control(return_yield) if node.block
54
+ end
55
+ false
56
+ when Macro::FormNode
57
+ #should really recurse in corresponding form escapes....
58
+ false
59
+ else true
60
+ end
61
+ }
62
+ end
63
+ end
64
+ end
@@ -1,6 +1,6 @@
1
1
  =begin
2
2
  rubymacros - a macro preprocessor for ruby
3
- Copyright (C) 2008 Caleb Clausen
3
+ Copyright (C) 2008, 2016 Caleb Clausen
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify
6
6
  it under the terms of the GNU Lesser General Public License as published by
@@ -16,7 +16,4 @@
16
16
  along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  =end
18
18
 
19
-
20
- class Macro
21
- VERSION="0.1.5"
22
- end
19
+ require 'rubymacros/version'
@@ -0,0 +1,19 @@
1
+ =begin
2
+ rubymacros - a macro preprocessor for ruby
3
+ Copyright (C) 2008, 2016 Caleb Clausen
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+ require 'macro'
@@ -0,0 +1,23 @@
1
+ =begin
2
+ rubymacros - a macro preprocessor for ruby
3
+ Copyright (C) 2008, 2016 Caleb Clausen
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+
20
+ class Macro
21
+ VERSION="0.1.6"
22
+ end
23
+ RubyMacros=Macro
@@ -1,3 +1,21 @@
1
+ =begin
2
+ rubymacros - a macro preprocessor for ruby
3
+ Copyright (C) 2008, 2016 Caleb Clausen
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU Lesser General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public License
16
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ =end
18
+
1
19
  class WeakKeyHash<Hash
2
20
  def initialize(&block)
3
21
  super
@@ -0,0 +1,60 @@
1
+ # -*- encoding: utf-8 -*-
2
+ =begin
3
+ rubymacros - a macro preprocessor for ruby
4
+ Copyright (C) 2008, 2016 Caleb Clausen
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Lesser General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License
17
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+ dir=File.dirname(__FILE__)
21
+ require "#{dir}/lib/rubymacros/version"
22
+ RubyMacros::Description=open("#{dir}/README.txt"){|f| f.read[/^==+ ?description[^\n]*?\n *\n?(.*?\n *\n.*?)\n *\n/im,1] }
23
+ RubyMacros::Latest_changes="###"+open("#{dir}/History.txt"){|f| f.read[/\A===(.*?)(?====)/m,1] }
24
+
25
+ Gem::Specification.new do |s|
26
+ s.name = "rubymacros"
27
+ s.version = RubyMacros::VERSION
28
+ s.date = Time.now.strftime("%Y-%m-%d")
29
+ s.authors = ["Caleb Clausen"]
30
+ s.email = %q{caleb (at) inforadical (dot) net}
31
+ s.summary = "RubyMacros is a lisp-like macro pre-processor for Ruby."
32
+ s.description = RubyMacros::Description
33
+ s.homepage = %{http://github.com/coatl/rubymacros}
34
+ s.rubyforge_project = %q{rubymacros}
35
+ s.license = %q{LGPL-2.1}
36
+
37
+ s.files = `git ls-files`.split
38
+ s.test_files = %w[test/test_all.rb]
39
+ s.require_paths = ["lib"]
40
+ s.bindir = "bin"
41
+ s.extra_rdoc_files = ["README.txt", "COPYING.LGPL"]
42
+ s.has_rdoc = true
43
+ s.rdoc_options = %w[--main README.txt]
44
+
45
+ s.rubygems_version = %q{1.3.0}
46
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 2
51
+
52
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency("redparse", ['>= 1.0.0'])
54
+ else
55
+ s.add_dependency("redparse", ['>= 1.0.0'])
56
+ end
57
+ else
58
+ s.add_dependency("redparse", ['>= 1.0.0'])
59
+ end
60
+ end