rubymacros 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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