rubymacros 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,15 @@
1
+ === 0.1.5 / 2009-07-04
2
+ * 4 Major Enhancements:
3
+ * all macros are now immediate, not delayed
4
+ * macro calls can accept blocks
5
+ * macro calls need not be inside a method
6
+ * form escapes can stand in for a method name in callsites
7
+ * 4 Minor Enhancements:
8
+ * macros can expand to nop by returning nil
9
+ * form escapes whose value is a symbol become callsites now
10
+ * forms can now be catenated together with + in the obvious way
11
+ * HashLiteralNode can be treated somewhat like a real hash, using #get
12
+
1
13
  === 0.1.4 / 2009-05-21
2
14
  * 1 Major Enhancement:
3
15
  * line numbers are now preserved in preprocessed code;
data/Rakefile CHANGED
@@ -19,8 +19,7 @@ require 'lib/macro/version.rb'
19
19
 
20
20
  readme=open("README.txt")
21
21
  readme.readline("\n== DESCRIPTION:")
22
- readme.readline("\n\n")
23
- desc=readme.readline("\n\n")
22
+ desc=readme.readline("\n==")
24
23
 
25
24
  hoe=Hoe.new("rubymacros", Macro::VERSION) do |_|
26
25
  _.author = "Caleb Clausen"
data/TODO CHANGED
@@ -4,6 +4,9 @@ macro options
4
4
  precedence for operator macros
5
5
  hygienic vs unhygienic
6
6
 
7
+ need to insert extra parens around form params
8
+ except only if it stands in for an rvalue...
9
+ not if its an lvalue, mvalue, cvalue, etc (bvalue?)
7
10
  static selector namespaces?
8
11
 
9
12
  other types of macro:
data/example/assert.rb CHANGED
@@ -1,18 +1,14 @@
1
1
  #this file uses macros! won't parse in normal ruby
2
- $Debug=1
3
- if $Debug
4
- macro assert(cond)
5
- if RedParse::OpNode===cond and /\A[=!]=\Z/===cond.op
6
- left,op,right=*cond
7
- :(fail 'expected '+^left.unparse+"(==#{^left}) to be "+
8
- ^op+" "+^right.unparse+"(==#{^right})" unless ^cond)
9
- else
10
- :(fail "expected #{:(^^cond)}, but was not true" unless ^cond)
2
+ macro assert(cond)
3
+ if $Debug
4
+ if RedParse::OpNode===cond and /\A[=!]=\Z/===cond.op
5
+ left,op,right=*cond
6
+ :(fail 'expected '+^left.unparse+"(==#{^left}) to be "+
7
+ ^op+" "+^right.unparse+"(==#{^right})" unless ^cond)
8
+ else
9
+ :(fail "expected #{:(^^cond)}, but was not true" unless ^cond)
10
+ end
11
11
  end
12
- end
13
- else
14
- macro assert(cond)
15
- end
16
12
  end
17
13
 
18
14
 
@@ -29,7 +25,7 @@ def test_assert
29
25
  assert(a==b) #oops, fails. msg="expected a(==1) to be == b(==2)"
30
26
  rescue Exception=>e
31
27
  assert("expected a(==1) to be == b(==2)"== e.message) #better be ok
32
- else fail
28
+ else puts "exception expected but was not seen"
33
29
  end
34
30
 
35
31
  begin
@@ -37,6 +33,6 @@ def test_assert
37
33
  rescue Exception=>e
38
34
  assert("expected nil, but was not true"== e.message) #better be ok
39
35
  #ok, that message didn't make a lot of sense...
40
- else fail
36
+ else puts "exception expected but was not seen"
41
37
  end
42
38
  end
@@ -1,4 +1,5 @@
1
1
  require 'macro'
2
+ $Debug=1
2
3
  Macro.require 'example/assert'
3
4
 
4
5
  test_assert
data/lib/macro.rb CHANGED
@@ -16,16 +16,11 @@
16
16
  along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  =end
18
18
 
19
- #$:.unshift "../redparse/lib"
20
- #warn "$: hacked up to find latest redparse"
21
-
22
19
  require 'rubygems'
23
20
  require 'redparse'
24
21
  require "macro/form"
25
22
  require "macro/version"
26
23
 
27
- warn "need to insert extra parens around form params"
28
-
29
24
  class Object # :nodoc:
30
25
  #as close as I can get to an empty binding (used below in Macro.eval)
31
26
  def Object.new_binding() # :nodoc:
@@ -204,6 +199,8 @@ class Macro
204
199
  # +session+:: the context in which this macro is being processed
205
200
  #
206
201
  def Macro.postpone node,session
202
+ return node #disable postponement
203
+
207
204
  filename=session[:filename]
208
205
  unless session[:@modpath_unsure]
209
206
  modpath=ConstantNode[nil,*session[:@modpath]]
@@ -409,8 +406,19 @@ class Macro
409
406
  node[0]=ParenedNode[ConstantNode[nil,"Object"]] #all macros are global for now... til we get scoped macros
410
407
  #sets receiver
411
408
 
409
+ #disable postponement (delayed macros) ... i think they're not necessary
410
+ expand=proc{|x| Node===x ? Macro.expand(x,macros,session) : x}
411
+ node.receiver= expand[node.receiver]
412
+ node.args.map! &expand if node.args
413
+ node.body= expand[node.body]
414
+ node.rescues.map! &expand if node.rescues
415
+ node.ensure_= expand[node.ensure_]
416
+ node.else_= expand[node.else_]
417
+ node.eval
418
+ macros[name.to_sym]=::Object.method("macro_"+name)
419
+ return node,false
420
+
412
421
  #node.eval #no, not here....
413
- # macros[name.to_sym]=self.name
414
422
 
415
423
  newnode=Macro.postpone node, session
416
424
 
@@ -471,14 +479,27 @@ class Macro
471
479
  #macro=macros[name.to_sym]=::Object.method(macro) if String===macro
472
480
  #refuse macro calls with receivers, blocks, varargs, or &args: not supported yet
473
481
  fail "macro receivers not supported yet" if receiver
474
- fail "macro blocks not supported yet" if block or blockparams
475
- fail "macro block args not supported yet" if UnOpNode===args.last and args.last.ident=="&@"
482
+ fail "macro blocky args not supported yet" if UnOpNode===args.last and args.last.ident=="&@"
476
483
  fail "macro varargs calls not supported yet" if UnaryStarNode===args.last
477
484
  fail if args.class!=Array
478
- newnode=macro.call *args
485
+ if block
486
+ newnode=macro.call *args do |*bparams|
487
+ if !blockparams
488
+ block
489
+ else
490
+ bparams=KWCallNode["nil"] if bparams.empty?
491
+ #warning: scoping rules for lvars in blocks not enforced here
492
+ #(rather serious violation of variable hygiene)
493
+ ParenedNode[ AssignNode[MultiAssign[*blockparams],'=',bparams]+block ]
494
+ end
495
+ end
496
+ else
497
+ newnode=macro.call *args
498
+ end
479
499
  #subi ? parent[i][subi]=newnode : parent[i]=newnode
480
500
 
481
501
  # and keep recursing, no matter what, by all means!!
502
+ newnode||=NopNode.new
482
503
  newnode=Macro.expand newnode,macros,session #just do it here
483
504
  newnode=OneLineParenedNode[newnode] #disable newlines in macro text
484
505
  return newnode,false #and not in caller
@@ -487,7 +508,7 @@ class Macro
487
508
 
488
509
  #postpone macro expansion in methods til method defn is executed
489
510
  class MethodNode
490
- def macro_expand(macros,session)
511
+ def old_macro_expand(macros,session)
491
512
  if session[:@expand_in_defs]
492
513
  session[:@expand_in_defs]=false
493
514
  expand=proc{|x| Node===x ? Macro.expand(x,macros,session) : x}
@@ -503,6 +524,16 @@ class Macro
503
524
  return Macro.postpone(self,session),false
504
525
  end
505
526
  end
527
+ def macro_expand(macros,session)
528
+ expand=proc{|x| Node===x ? Macro.expand(x,macros,session) : x}
529
+ self.receiver= expand[receiver]
530
+ args.map! &expand if args
531
+ self.body= expand[body]
532
+ rescues.map! &expand if rescues
533
+ self.ensure_= expand[ensure_]
534
+ self.else_= expand[else_]
535
+ return self,false
536
+ end
506
537
  end
507
538
 
508
539
  #disable macro definitions within classes and modules
@@ -622,6 +653,10 @@ class Macro
622
653
  return super
623
654
  end
624
655
  end
656
+
657
+ def image
658
+ "^"+first.image
659
+ end
625
660
  end
626
661
 
627
662
  class MacroNode < ValueNode
@@ -641,6 +676,25 @@ class Macro
641
676
  fail "unrecognized method header: #{header}"
642
677
  end
643
678
  @data=replace [receiver,header,args,body,rescues,else_,ensure_]
679
+
680
+ =begin hmm, maybe not a good idea....
681
+ #quote parameters to yield within macro
682
+ walk{|cntr,i,subi,item|
683
+ case item
684
+ when KWCallNode;
685
+ if item.name=="yield"
686
+ raise ArgumentError if item.block or item.blockparams
687
+ if item.params
688
+ raise ArgumentError if UnAmpNode===item.params.last
689
+ item.params.map!{|param| FormNode.new(nil,ParenedNode[param]) }
690
+ end
691
+ false
692
+ else true
693
+ end
694
+ else true
695
+ end
696
+ }
697
+ =end
644
698
  end
645
699
 
646
700
  alias else_ elses
@@ -698,6 +752,7 @@ class Macro
698
752
  Expr.-, RescueNode.*, ElseNode.-, EnsureNode.-,
699
753
  'end'
700
754
  ]>>MacroNode,
755
+ -[ParenedNode, '(', Expr.-, ')', BlockNode.-, KW('do').~.la]>>CallNode,
701
756
  ]
702
757
  end
703
758
  def wants_semi_context
data/lib/macro/form.rb CHANGED
@@ -48,6 +48,11 @@ class Macro
48
48
  rebuild_transform
49
49
  end
50
50
 
51
+ def initialize_ivars
52
+ rebuild_transform
53
+ super
54
+ end
55
+
51
56
  # Initialize the transform and create all the form escapes that are
52
57
  # used in this form
53
58
  def rebuild_transform
@@ -114,15 +119,20 @@ class Macro
114
119
  ":("+text.unparse(o)+")"
115
120
  end
116
121
 
117
- # Called when the form is evaluated to ensure that the abstract form
118
- # in the parse tree is a concrete form that can be modified (makes a
122
+ # Called when the form is evaluated to convert the abstract form
123
+ # of the parse tree into a concrete form that can be modified (makes a
119
124
  # copy of the form).
120
125
  #
121
126
  # +transform+:: the transform to use in the deep copy
122
127
  #
123
128
  def reify transform
124
129
  transform.each_pair{|k,v|
125
- transform[k]=Macro.quote(v) unless Node===v or VarNameToken===v
130
+ case v
131
+ when Node; next
132
+ when Symbol; v=CallNode[nil,v.to_s]
133
+ else v=Macro.quote v
134
+ end
135
+ transform[k]=v
126
136
  }
127
137
  deep_copy(transform)
128
138
  end
@@ -161,17 +171,13 @@ class Macro
161
171
  # RedParse::SomeNodeType[ some transform of code ]
162
172
  #
163
173
  def parses_like
164
- # TODO: either split this into mulitple lines or multiple methods
165
- # possibly formname() should return the ConstantNode portion of
166
- # the below expression (so that we have one "name" for the form
167
- # instead of two representations of the same name)
168
- CallSiteNode[CallSiteNode[ConstantNode[nil,"Macro","Names",formname], "reify", [@transform],nil,nil], "text", nil,nil,nil]
169
- #:(::Macro::Names::^(formname).reify.text)
174
+ CallSiteNode[CallSiteNode[formname, "reify", [@transform]], "text"]
175
+ #:(^(formname).reify(^@transform).text)
170
176
  end
171
177
 
172
178
  # Lazily evaluate the name of the form and return it
173
179
  def formname
174
- @formname ||= ::Macro::Names.request(self)
180
+ @formname ||= ConstantNode[nil,"Macro","Names",::Macro::Names.request(self)]
175
181
  end
176
182
  end
177
183
 
data/lib/macro/version.rb CHANGED
@@ -18,5 +18,5 @@
18
18
 
19
19
 
20
20
  class Macro
21
- VERSION="0.1.4"
21
+ VERSION="0.1.5"
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubymacros
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Caleb Clausen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-22 00:00:00 -07:00
12
+ date: 2009-07-07 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,7 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.12.2
34
34
  version:
35
- description: Macros are programmed in ruby itself. And since parse trees are represented in RedParse format, they're easier to use (programatically) and more object-oriented than other available ruby parsetree formats. (RedParse Node format is actually designed to be straightforward to use and to represent the structure of ruby source code very closely.)
35
+ description: RubyMacros is a lisp-like macro pre-processor for Ruby. More than just a purely textual substitution scheme, RubyMacros can manipulate and morph Ruby parse trees (in the form of RedParse Nodes) at parse time in just about any way you see fit. Macros are programmed in ruby itself. And since parse trees are represented in RedParse format, they're easier to use (programatically) and more object-oriented than other available ruby parsetree formats. (RedParse Node format is actually designed to be straightforward to use and to represent the structure of ruby source code very closely.) ==
36
36
  email: rubymacros-owner @at@ inforadical .dot. net
37
37
  executables: []
38
38
 
@@ -97,6 +97,6 @@ rubyforge_project: rubymacros
97
97
  rubygems_version: 1.3.1
98
98
  signing_key:
99
99
  specification_version: 2
100
- summary: Macros are programmed in ruby itself.
100
+ summary: RubyMacros is a lisp-like macro pre-processor for Ruby.
101
101
  test_files:
102
102
  - test/test_all.rb